zoukankan      html  css  js  c++  java
  • CF1237H. Balanced Reversals

    题目大意

    给出长为n(n是偶数)的01串S,每次可以把一个长度为偶数的前缀翻转,构造至多n+1次操作把串S变成串T或输出无解

    n<=4000

    题解

    讲杂题时并没有给出操作次数限制,所以以为可以乱做,想每次翻到末尾,这样是3/2n次

    首先把两个合成一组,如果01+10、00、11的个数不相等就无解

    然后考虑从头开始构造,维护一段前缀[1,i]使得rev(S[1,i])=T[1,i],接着每次用两次操作即可把后面的某个接到前面来,最后再把[1,n-2]翻转即可得到T,过程中由于翻了两次所以01和10不会变

    问题是使一开始的01和10个数相等,找到ST中0110差绝对值较大者,将其的一个前缀翻转

    因为差的绝对值越大说明01的个数越靠近0或n/2,反过来的过程中一定会与另一个相遇

    总操作次数为2(n/2-1)+1+1=n

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define abs(x) ((x)>0?(x):-(x))
    #define ll long long
    //#define file
    using namespace std;
    
    int a[4001],b[4001],sum[4],Sum[4],Q,n,N,i,j,k,l,Ls,tot;
    int ans[4002];
    char S[4001],T[4001];
    
    void swap(int &x,int &y) {int z=x;x=y;y=z;}
    int turn(char a,char b) {if (a==b) {return (a=='0')?2:3;} if (a=='0') return 0;return 1;}
    void rev(int *a,int t)
    {
    	int i;
    	fd(i,t/2,1) swap(a[i],a[t-i+1]);
    	fo(i,1,t) if (a[i]<=1) a[i]^=1;
    }
    
    int main()
    {
    	#ifdef file
    	freopen("CF1237H.in","r",stdin);
    	#endif
    	
    	scanf("%d",&Q);
    	for (;Q;--Q)
    	{
    		scanf("%s",S+1),scanf("%s",T+1);
    		n=strlen(S+1),tot=0,N=n/2;
    		memset(sum,0,sizeof(sum));
    		memset(Sum,0,sizeof(Sum));
    		fo(i,1,N) a[i]=turn(S[i*2-1],S[i*2]),++sum[a[i]];
    		fo(i,1,N) b[i]=turn(T[i*2-1],T[i*2]),++Sum[b[i]];
    		if (sum[0]+sum[1]!=sum[0]+sum[1] || sum[2]!=Sum[2] || sum[3]!=Sum[3]) {printf("-1
    ");continue;}
    		
    		Ls=-1,tot=0;
    		if (sum[0]!=Sum[0])
    		{
    			if (abs(sum[0]-sum[1])>abs(Sum[0]-Sum[1]))
    			{
    				fo(i,1,N)
    				if (a[i]<=1)
    				{
    					--sum[a[i]],++sum[a[i]^1];
    					if (sum[0]==Sum[0]) {rev(a,i);ans[++tot]=i;break;}
    				}
    			}
    			else
    			{
    				fo(i,1,N)
    				if (b[i]<=1)
    				{
    					--Sum[b[i]],++Sum[b[i]^1];
    					if (sum[0]==Sum[0]) {rev(b,i);Ls=i;break;}
    				}
    			}
    		}
    		
    		fo(i,1,N-1)
    		{
    			fo(j,i,N)
    			if (a[j]==b[i])
    			{
    				if (j>1) rev(a,j-1),ans[++tot]=j-1;
    				rev(a,j),ans[++tot]=j;
    				break;
    			}
    		}
    		if (N>1) rev(a,N-1),ans[++tot]=N-1;
    		
    		if (Ls>-1) ans[++tot]=Ls;
    		printf("%d
    ",tot);
    		fo(i,1,tot) printf("%d ",ans[i]*2);
    		printf("
    ");
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    解析·玄学 模拟退火
    NOIP2018 集训(三)
    NOIP2018 集训(二)
    NOIP2018 集训(一)
    动画制作-cartoon
    视频压缩-video cutter
    [里程碑]media pro sdk 1.0 finished
    图像去水印-image inpainting
    地平线检测horizon line detection
    二维数据缺失补全
  • 原文地址:https://www.cnblogs.com/gmh77/p/14026671.html
Copyright © 2011-2022 走看看