1 条题解

  • 0
    @ 2025-8-24 21:43:00

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Delva
    **

    搬运于2025-08-24 21:43:00,当前版本为作者最后更新于2018-10-23 08:14:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    贪心,枚举,差分

    因为同一个点翻转两次就与没有翻转的效果相同了,因此我们有一个贪心策略为:

    从左到右对于出现的每一个B翻转一次从当前点开始的区间,就能保证是最优解。

    样例的模拟:

    如果当前翻转的区间长度为3

    粗体表示当前下标

    B B F B F B B

    (B B F) B F B B

    F F B B F B B

    F F B B F B B

    F F B B F B B

    F F (B B F) B B

    F F F F B B B

    F F F F B B B

    F F F F B B B

    F F F F (B B B)

    F F F F F F F

    F F F F F F F

    F F F F F F F

    但是我们会发现这样是n^2的,再枚举长度,就变为了n^3.因此,需要对区间翻转差分一下,总时间复杂度就是n^2的了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 10009;
    int n;
    bool A[maxn],B[maxn];
    int main(){
    	scanf("%d",&n);
    	char ch;
    	for(int i=1;i<=n;++i){
    		cin>>ch;A[i]=ch=='B'?0:1;
    	}
    	int mincnt=0x7fffffff,anslen;
    	for(int len=1;len<=n;++len){
    		memset(B,0,sizeof B);
    		bool b=0,flag=1;int cnt=0;//flag记录当前长度是否有解
    		for(int i=1;i<=n;++i){//因为区间翻转只有状态0和1,所以用^代替+和-
    			b^=B[i];//数组B为记录差分的数组
    			if(!(A[i]^b)){//若当前位置为0
    				if(i+len-1>n){flag=0;break;}//唯一的失败条件:一次翻转的长度大于剩余的长度
    				b^=1,B[i+len]^=1;
    				++cnt;
    			}
    		}
    		if(flag){if(cnt<mincnt)mincnt=cnt,anslen=len;}
    	}printf("%d %d\n",anslen, mincnt);
    } 
    
    • 1

    信息

    ID
    1947
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者