給個串,只能用操作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\n",lans); 67 for (int i=1;i<=lans;i++) printf("%d ",ans[i]); 68 return 0; 69 }
還有一種好理解的逐個字符構造,也是從后往前。
比如說現在串是AzB,A的前綴已經是t的一個后綴,z是想加在A前面的字符,B是剩下的。然后這樣:AzB->B'zA'->AB'z->zAB'。搞定。操作次數3*n。
(好吧這是評論寫的)