[agc019d]Shift and Flip

来源:互联网 发布:java web 插件式开发 编辑:程序博客网 时间:2024/06/05 07:29

前言

这是一个简单题但是我细节一开始没想清楚?

题目大意

两个01字符串a和b,你可以把a左旋、右旋。
还有一种翻转操作,如果bi=1那么你可以把ai取反。
问a变成b最少操作次数。

做法

先判断无解,当b中有1时一定有解,全0时如果a不是全0就会GG。
然后看看怎么算答案。
先对每个位置预处理至少左移/右移多少次才能让它对应一个b中有1的位置,分别记为L和R。
我们可以枚举最后的对应位置i。
然后我们可以考虑最终是右移对齐b的还是左移对齐b的。
以右移为例。
假如要右移cnt步。
我们考虑所有R>cnt的需要翻转的位置,你要么只能再右移长一点,最后再左移回来,要么你要尝试一开始左移至少L步。
也就是对于每一个这样的位置,都有两种选择,左移满足或右移满足。
如果全部选择左移满足,那么在移动的步数上是最大左移步数*2+cnt。
如果选择过右移满足,那么在移动的步数上是最大左移步数*2+最大右移步数*2-cnt。
我们可以枚举最大左移步数,然后找到对应的最大右移步数。
计算最小答案即可。
只需要最小化移动步数就行了,翻转操作的次数是固定的。
复杂度我写的是n^2 log n,-_-。

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=2000+10;char s[maxn];int a[maxn],b[maxn],c[maxn],L[maxn],R[maxn];bool bz[maxn];int i,j,k,l,t,n,m,ans,num,sum,cnt,mx,mi,top;bool czy,gjx;bool cmpL(int x,int y){    return L[x]<L[y];}bool cmpR(int x,int y){    return R[x]<R[y];}int main(){    scanf("%s",s+1);    n=strlen(s+1);    czy=1;    fo(i,1,n){        a[i]=s[i]-'0';        if (a[i]) czy=0;    }    scanf("%s",s+1);    gjx=1;    fo(i,1,n){        b[i]=s[i]-'0';        if (b[i]) gjx=0;    }    if (gjx){        if (czy) printf("0\n");else printf("-1\n");        return 0;    }    fo(i,1,n){        j=i;        while (!b[j]){            L[i]++;            if (j==1) j=n;            else j--;        }        j=i;        while (!b[j]){            R[i]++;            if (j==n) j=1;            else j++;        }    }    ans=1000000000;    fo(i,1,n){        fo(j,1,n) bz[j]=0;        sum=0;        j=i;        fo(k,1,n){            if (a[j]!=b[k]) bz[j]=1,sum++;            if (j==n) j=1;else j++;        }        cnt=(i==1?0:n-i+1);        top=0;        fo(j,1,n)            if (bz[j]&&R[j]>cnt) c[++top]=j;        sort(c+1,c+top+1,cmpL);        mx=0;mi=5*n;        if (top) mi=min(mi,L[c[top]]*2+cnt);        fd(j,top,1){            mx=max(mx,R[c[j]]);            if (j>1) mi=min(mi,L[c[j-1]]*2+mx*2-cnt);        }        if (top) mi=min(mi,mx*2-cnt);        if (!top) mi=cnt;        num=mi;        ans=min(ans,num+sum);        cnt=i-1;        top=0;        fo(j,1,n)            if (bz[j]&&L[j]>cnt) c[++top]=j;        sort(c+1,c+top+1,cmpR);        mx=0;mi=5*n;        if (top) mi=min(mi,R[c[top]]*2+cnt);        fd(j,top,1){            mx=max(mx,L[c[j]]);            if (j>1) mi=min(mi,R[c[j-1]]*2+mx*2-cnt);        }        if (top) mi=min(mi,mx*2-cnt);        if (!top) mi=cnt;        num=mi;        ans=min(ans,num+sum);    }    printf("%d\n",ans);}
原创粉丝点击