题目链接:https://vjudge.net/contest/397850#problem/C 题意:将01字串a可以进行多少次操作变成b。 操作:将前缀i前面的数(包括i)是1的话变成0(是0的话变为1),然后再将其到前缀i之间的数反转。输出最少的操作数,并写出前缀i。 题解:因为需要反转,所以优先考虑后面的,又因为后面的b[i]是由a[0]变成的。所以需要判断是否需要先变a[0]。如果a[0]和b[i]相等的话,因为要由1变成0,所以需要先改变a[0]。然后再将其反转 代码:(复杂度(n*n))
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #define maxn 1200 using namespace std; int a[maxn],b[maxn]; string aa,bb; int sol[3*maxn]; int n;//串的长度 void solve(int k) { for(int i=0;i<=k;i++) a[i]=1-a[i]; for(int i=0;i<=k/2;i++) swap(a[i],a[k-i]); } void duru() { scanf("%d",&n); getchar();//getline也读空行,所以需要吸收 //01字串是连着的,所以需要用字符来处理 getline(cin,aa); for(int i=0;i<n;i++) a[i]=(int)(aa[i]-'0'); getline(cin,bb); for(int i=0;i<n;i++) b[i]=bb[i]-'0'; } int main() { int t; scanf("%d",&t); while(t--) { int num=0;//操作数 duru(); for(int i=n-1;i>=0;i--) { if(a[i]==b[i]) continue; if(a[0]==b[i]) { num++; sol[num]=1;//先变第一个 } num++; sol[num]=i+1; solve(i); } printf("%d ",num); for(int j=1;j<=num;j++) printf("%d ",sol[j]); printf("\n"); } return 0; }hard版本n<=1e5,所以肯定会超时,所以简化修改交换值得那一步,然后用正序和逆序来代替。l,r表示最左侧和最右侧。
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #define maxn 120000 using namespace std; int a[maxn],b[maxn]; string aa,bb; int sol[3*maxn]; int n;//串的长度 void duru() { scanf("%d",&n); getchar();//getline也读空行,所以需要吸收 //01字串是连着的,所以需要用字符来处理 getline(cin,aa); for(int i=0;i<n;i++) a[i]=(int)(aa[i]-'0'); getline(cin,bb); for(int i=0;i<n;i++) b[i]=bb[i]-'0'; } int main() { int t; scanf("%d",&t); while(t--) { int num=0;//操作数 duru(); int l=0,r=n-1;//最左侧,最右侧 int xu=1;//1表示正序,-1表示逆序 for(int i=n-1;i>=0;i--) { if(xu==1)//正序 { if(a[r]==b[i])//最右边的和他比较,所以是r和他比 { r--; continue; } if(a[l]==b[i]) { num++; sol[num]=1;//先变第一个 } num++; l++; sol[num]=i+1; xu=-1; } else if(xu==-1) { if(a[l]!=b[i])//此时逆序l是最右边,所以l和他比 { l++; continue; } if(a[r]!=b[i]) { num++; sol[num]=1;//先变第一个 } r--; num++; sol[num]=i+1; xu=1; } } printf("%d ",num); for(int j=1;j<=num;j++) printf("%d ",sol[j]); printf("\n"); } return 0; }