3 条题解

  • 2
    @ 2024-11-18 13:56:09

    贴个二分代码,跑得比spq的O(N)做法快
    思路: 假设1的数量是cc。如果答案是xx,那么我们最多删除了xx个1,并且最多留下了xx个0。如果cx+1c \ge x+1,一定满足要求。因此,答案存在单调性,我们考虑对区间[0,c][0, c]使用二分。

    我们实现一个数组pospos,其中posipos_i是字符串中第ii个1的位置。在checkcheck函数中,我们枚举每个删完后剩下的区间,并判断其中0的个数是否x\le x
    核心代码:

    signed main()
    {
    	setIO();
    	string str; cin>>str;
    	vector<int> pos;
    	for(int i=0; i<str.size(); i++)
    		if(str[i]=='1')
    			pos.eb(i);
    	if(pos.empty() || pos.back()-pos.front()==pos.size()-1)
    		return cout<<0<<endl, 0;
    	int l=0, r=pos.size(), res=r;
    	auto check=[&](int mid) -> bool
    	{
    		int k=pos.size(), x=k-mid;
    		for(int i=0; i<=mid; i++)
    		{
    			int l=pos[i], r=pos[i+x-1];
    			if(r-l+1-x<=mid)
    				return true;
    		}
    		return false;
    	};
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid)) r=mid-1, res=mid;
    		else l=mid+1;
    	}
    	cout<<res<<endl;
    	return 0;
    }
    
    • -1
      @ 2024-11-18 13:55:23

      这里有o(n)解法:

      共n个01字符 设其中共cnt个"0",最佳删s个数,其中删t个"1". 那么剩下的0即可表示为cnt-s+t。 那么题意就是求max(t,cnt-s+t)。 将t提出 即求t+max(0,cnt-s)。

      现在可以猜想结论:在s=cnt时最优,下证: 当s取cnt-1时: max部分一定增大1 而t部分可能减小一也可能不减小 因此当s取小于cnt时一定不更优。 当s取cnt+1时: t部分可能增大一也可能不增大 而max部分一定减小 因此当s取大于cnt时一定不更优。 综上 s=cnt时一定最优。

      运用结论 暴力o(n^2)即可优化为o(n)。

      #include<bits/stdc++.h>
      using namespace std;
      const int N=2000005;
      long long n;
      string s;
      int cnt=0;
      int f[N];
      int a[N];
      int b[N];
      int ans=INT_MAX;
      int main(){
      	cin>>s;
      	n=s.length();
      	for(int i=0;i<n;i++){
      		f[i+1]=s[i]-'0';
      		if(s[i]=='0'){
      			cnt++;
      		}
      	}
      	for(int i=1;i<=n;i++){
      		if(f[i]==1){
      			a[i]++;
      		}
      		a[i]+=a[i-1];
      	}
      	for(int i=n;i>=1;i--){
      		if(f[i]==1){
      			b[i]++;
      		}
      		b[i]+=b[i+1];
      	}
      	for(int i=0;i<=cnt;i++){
      		ans=min(ans,a[i]+b[n-cnt+i+1]);
      	}
      	cout<<ans;
      	return 0;
      }
      
      • -2
        @ 2024-10-31 16:25:15

        分析

        tag:二分、滑动窗口

        由于两个操作是从两端删除任意长度,所以本质就是保留一个子串,问题转化为找到一个子串,使得max(max(长度- 子串中11数量,子串中00的数量))最小,我们二分答案,维护一个滑动窗口。二分答案区间为[0,cnt0][0,cnt0],一眼看去我们应该取max(cnt0,cnt1)max(cnt0,cnt1)为右端点,对于一个子串当你删掉的11少于00的时候,那你为何不能再删多几个11达到和剩余的00相同数目,还说不定能删更多的00呢导致更优的答案,所以对于初始字符串二分的答案区间为[0,cnt0][0,cnt0],也就是子串最多能剩多少个00checkcheck的话维护一个滑动窗口,当当前窗口00的数量超过了midmid就左端点右移,对于每个窗口统计答案,判断剩下的11是否也小于等于midmid,也就是是否符合max(del1,cnt0)midmax(del1,cnt0) \leq mid,不符合的话取右边区间,符合的话记录答案并且取左区间。

        参考代码

        #include <bits/stdc++.h>
        
        using namespace std;
        const int N = 2e6 + 10;
        char s[N];
        int n;
        bool check(int mid, int tot1) {
            int l = 0;
            int cnt0 = 0, cnt1 = 0;
            for (int r = 0; r < n; r++) {
                if (s[r] == '1') {
                    cnt1++;
                } else {
                    cnt0++;
                }
                while (cnt0 > mid) {
                    if (s[l] == '1') {
                        cnt1--;
                    } else {
                        cnt0--;
                    }
                    l++;
                }
                int del1 = tot1 - cnt1;
                if (del1 <= mid) {
                    return true;
                }
            }
            return false;
        }
        
        
        int main() {
            scanf("%s", s);
            n = strlen(s);
            int cnt1 = 0;
            for (int i = 0; i < n; i++) cnt1 += s[i] - '0';
            int cnt0 = n - cnt1;
            int l = 0, r = cnt0;
            int ans = 0;
            while (l <= r) {
                int mid = (l + r) / 2;
                if (check(mid, cnt1)) {
                    ans = mid;
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            }
            printf("%d\n", ans);
            return 0;
        }
        
        • 1

        信息

        ID
        20
        时间
        1000ms
        内存
        256MiB
        难度
        8
        标签
        递交数
        113
        已通过
        17
        上传者