CF1237H

这题大概是noip难度,为什么CF上会评到3200?qwq
 
首先不难想到把两个字符压成一个来处理,大概就是:
 
0001100010->00 01 10 00 10
 
如果初始串中“00”的个数不等于目标串中“00”的个数,显然无解。对于“11”,也一样。
 
我们从第一组(目标串两个字符为一组)开始,依次匹配,具体来说,如下:([]里的字符是匹配好的字符,{}为这一次翻转的区间)
 
初始串:1001100011
目标串:00 11 01 01 10
 
目标串第一组字符是“00”,从初始串中找到“00”,并将其翻转到最前面。
 
目前:1001100011->{00011001}11->[00]01100111
目标:00 11 01 01 10
 
目标串第二组字符是“11”,从目前串中找到“11”,将其与已匹配好的“00”连在一起,再把它们翻到最前面。
 
目前:[00]01100111->{10011000}11->{1100011001}->[1100]011001
目标:00 11 01 01 10
 
这时大家可能会疑惑:前面四个字符不匹配呀?要不要再翻转一次使它们匹配?答案是不需要(原因见下文)。
 
继续匹配:目标第三组字符是“01”,从从目前串中找到“01”(如果有多个则随便找一个,如果没有?待会再说),将其与已匹配好的“0011”连在一起,再把它们翻到最前面。
 
目前:[1100]011001->{0011}011001->{101100}1001->[101100]1001
目标:00 11 01 01 10
 
继续匹配。
 
目前:[101100]1001->{01001101}01->{1010110010}->[10101100]10->{00110101}10->[00 11 01 01 10]
目标:00 11 01 01 10
 
匹配成功了!大功告成!可以看到,我们先将前2k个字符“倒序匹配”(目前状态前2k个字符反过来就是目标状态前2k个字符),再将前2(k+1)个字符“倒序匹配”,一直这么下去,直到匹配完成。示意图前2k个字符是"000110",x是两个字符“00”,"..."表示尚未匹配的字符)
 
当前状态:[011000]...(x)...->{...000110}(x)...-> {(x,011000...)...}->[x,011000]...
目标状态:(000110,x)...
 
但是,在匹配第i组字符的时候,找不到对应的字符怎么办?举个例子,i=3。
 
当前状态:[0011]100010
目标状态:11 00 01 10 00
 
目标第3组字符是“01”,可是当前状态中没有一组字符是“01”,怎么办呢?
 
注意到对于每一组字符,匹配前后当前串中未匹配字符中“01”和“10”不会颠倒(就是“01”匹配后还是“01”,“10”同理,具体可以回顾之前的匹配过程)。于是,我们只要想办法是初始串中“01”的个数和目标串中“01”的个数相同即可。方法很简单,翻转初始串和目标串个一次即可。怎么翻转目标串呢?打上标记,把初始串翻转成翻转后的目标串,然后再变成翻转前的目标串就好了。很明显,可以通过翻转初始串和目标串各至多一次来使两串中“01”的个数相等(感性理解即可)。
最后总结一下,先预处理,再挨个匹配,最后输出方案就可以了。
 
明显这么做翻转次数不会超过n+1次(预处理两次,匹配每两个字符两次,最后一组字符一次)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int _abs(int x){return x>0?x:-x;}
int n,m,q,v;
struct Pair{
 bool A,B;
}s[2000],t[2000];
char c1,c2;
int cnt[8],ans[4005];
int s0[2000],s1[2000];
int t0[2000],t1[2000];
void read(void)
{
 while((c1=getchar())=='\n'||c1==' ');
 c2=getchar();
 s[n].A=c1-'0'; s[n++].B=c2-'0';
 while((c1=getchar())!='\n'&&c1!=' '){
  s[n].A=c1-'0'; s[n++].B=getchar()-'0';
 }
 while((c1=getchar())=='\n'||c1==' ');
 c2=getchar();
 t[m].A=c1-'0'; t[m++].B=c2-'0';
 while((c1=getchar())!='\n'&&c1!=' '){
  t[m].A=c1-'0'; t[m++].B=getchar()-'0';
 }
 return;
}
inline void reverseS(int i)
{
 ans[++q]=(i+1)<<1;
 for(int j=0;(j<<1)<=i;j++){
  swap(s[j],s[i-j]);
  swap(s[j].A,s[j].B);
  if((j<<1)!=i)
   swap(s[i-j].A,s[i-j].B);
 }
 return;
}
inline void reverseT(int i)
{
 for(int j=0;(j<<1)<=i;j++){
  swap(t[j],t[i-j]);
  swap(t[j].A,t[j].B);
  if((j<<1)!=i)
   swap(t[i-j].A,t[i-j].B);
 }
 return;
}
inline void debug(void)
{
 for(int i=0;i<n;i++)
  printf("%d%d ",s[i].A,s[i].B);
 putchar('\n');
 for(int i=0;i<n;i++)
  printf("%d%d ",t[i].A,t[i].B);
 putchar('\n');
 printf("--------------------------\n");
 return;
}
inline void init(void)
{
 s0[0]=t0[0]=s1[0]=t1[0]=0;
 for(int i=0;i<n;i++){
  if(i>0){
   s0[i]=s0[i-1]; s1[i]=s1[i-1];
   t0[i]=t0[i-1]; t1[i]=t1[i-1];
  }
  if(s[i].A==0&&s[i].B==1)
   s0[i]++;
  if(s[i].A==1&&s[i].B==0)
   s1[i]++;
  if(t[i].A==0&&t[i].B==1)
   t0[i]++;
  if(t[i].A==1&&t[i].B==0)
   t1[i]++;
 }
 return;
}
inline void rev(void)
{
 if(s0[n-1]==t0[n-1])
  return;
 for(int i=0;i<n;i++){
  if(s0[n-1]-s0[i]+s1[i]==t0[n-1]){
   reverseS(i); return;
  }
  if(s0[n-1]==t0[n-1]-t0[i]+t1[i]){
   reverseT(v=i); return;
  }
  for(int j=0;j<n;j++)
   if(s0[n-1]-s0[i]+s1[i]==t0[n-1]-t0[j]+t1[j]){
    reverseS(i); reverseT(v=j);
    return;
   }
 }
}
inline int find(int x)
{
 for(int i=x;i<n;i++)
  if(s[i].A==t[x].A&&s[i].B==t[x].B)
   return i;
 return -1;
}
void solve(void)
{
 n=m=0; q=v=-1;
 memset(cnt,0,sizeof(cnt));
 read();
 for(int i=0;i<n;i++){
  cnt[s[i].A*2+s[i].B]++;
  cnt[t[i].A*2+t[i].B+4]++;
 }
 if(cnt[0]!=cnt[4]||cnt[3]!=cnt[7]||cnt[1]+cnt[2]!=cnt[5]+cnt[6]){
  printf("-1\n");
  return;
 }
 init(); rev();
 for(int i=0;i<n;i++){
  int t=find(i);
  if(t>0) reverseS(t-1);
  if(i!=n-1) reverseS(t);
 }
 if(v!=-1){
  reverseS(v);
  reverseT(v);
 }
 printf("%d\n",q+1);
 for(int i=0;i<=q;i++)
  printf("%d ",ans[i]);
 putchar('\n');
 return;
}
int main(void)
{
 int T;
 scanf("%d",&T);
 while(T--)
  solve();
 return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/2005lz/p/12821417.html