Codeforces936C. Lock Puzzle

给个串,只能用操作shift x表示把后面x个字符翻转后放到串的前面。问s串怎么操作能变t串。n<=2000,操作次数<=6100。

打VP时这转来转去的有点晕。。。

可以想一种逐步构造的方法,即从一个小的完成构造的部分通过一顿操作,在不影响这部分的前提下扩展。

好吧我看题解了,直接丢图,是从abc扩展成xabcy的方法,如果反了就把他最后再倒过来。

操作次数是$frac{5}{2}n$的,复杂度$kn$,$k$指操作次数。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 //#include<map>
 6 #include<math.h>
 7 //#include<time.h>
 8 //#include<complex>
 9 #include<algorithm>
10 using namespace std;
11  
12 int n;
13 #define maxn 10011
14 char s[maxn],t[maxn];int cnts[30],cntt[30],ans[maxn],lans=0;
15 
16 char tmp[maxn];
17 void shift(int x)
18 {
19     if (x==0) {lans--; return;}
20     memcpy(tmp,s,sizeof(char)*(n+3));
21     int cnt=0; x=n-x+1;
22     for (int i=n;i>=x;i--) s[++cnt]=tmp[i];
23     for (int i=1;i<x;i++) s[++cnt]=tmp[i];
24 }
25 
26 int findpos(int p,int rr)
27 {
28     for (int i=rr;i;i--)
29         if (s[i]==t[p]) return i;
30     return maxn*2;
31 }
32 
33 int main()
34 {
35     scanf("%d",&n);
36     scanf("%s",s+1); scanf("%s",t+1);
37     for (int i=1;i<=n;i++) cnts[s[i]-'a']++,cntt[t[i]-'a']++;
38     for (int i=0;i<26;i++) if (cnts[i]!=cntt[i]) {puts("-1"); return 0;}
39     
40     int p1=(1+n)>>1,p2=p1;
41     int p=findpos(p1,n); p1--; p2++;
42     if (p!=n) {ans[++lans]=n-p; shift(n-p);}
43     bool rev=0;
44     for (int now=1,p;p1;p1--,p2++,now+=2,rev^=1)
45     {
46         if (rev==0) p=findpos(p1,n-now); else p=findpos(p2,n-now);
47         shift(ans[++lans]=n-p);
48         shift(ans[++lans]=n);
49         shift(ans[++lans]=now);
50         if (rev==0) p=findpos(p2,n); else p=findpos(p1,n);
51         shift(ans[++lans]=n-p+1);
52         shift(ans[++lans]=p-now-2);
53     }
54     if (n&1) {if (rev) shift(ans[++lans]=n);}
55     else
56     {
57         if (rev) shift(ans[++lans]=n-1);
58         else
59         {
60             shift(ans[++lans]=n-1);
61             shift(ans[++lans]=1);
62             shift(ans[++lans]=n);
63         }
64     }
65     
66     printf("%d
",lans);
67     for (int i=1;i<=lans;i++) printf("%d ",ans[i]);
68     return 0;
69 }
View Code

还有一种好理解的逐个字符构造,也是从后往前。

比如说现在串是AzB,A的前缀已经是t的一个后缀,z是想加在A前面的字符,B是剩下的。然后这样:AzB->B'zA'->AB'z->zAB'。搞定。操作次数3*n。

(好吧这是评论写的)

原文地址:https://www.cnblogs.com/Blue233333/p/8477002.html