给出字符串s和t,以及s的长度n的一个全排列,求按照这个排列依次删除s的字符,删到何时s中不含子序列t。
解法一:
t中的每个字符的位置在s中跳啊跳,合法的情况下t中的字符在s中的位置应该是单调递增的,因此让t中的字符在s中建的邻接表里跳啊跳就好了。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<iostream> 8 using namespace std; 9 10 #define maxs 200011 11 char s[maxs];int ls; 12 char t[maxs];int lt; 13 int first[30],next[maxs],P[maxs]; 14 bool vis[maxs]; 15 bool Play(int x) 16 { 17 if (x==lt-1) return 1; 18 if (P[x+1]<=P[x]) 19 { 20 while (P[x+1]!=-1 && (P[x+1]<=P[x] || vis[P[x+1]])) P[x+1]=next[P[x+1]]; 21 if (P[x+1]==-1) return 0; 22 return Play(x+1); 23 } 24 return 1; 25 } 26 int x; 27 int find(int x) 28 { 29 int L=0,R=lt-1; 30 while (L<R) 31 { 32 int mid=(L+R)>>1; 33 if (x<=P[mid]) R=mid; 34 else L=mid+1; 35 } 36 return L; 37 } 38 int main() 39 { 40 scanf("%s",s);ls=strlen(s); 41 scanf("%s",t);lt=strlen(t); 42 memset(first,-1,sizeof(first)); 43 for (int i=ls-1;i!=-1;i--) 44 { 45 int now=s[i]-'a'+1; 46 next[i]=first[now]; 47 first[now]=i; 48 } 49 int ans=0; 50 for (int i=0;i<lt;i++) 51 P[i]=first[t[i]-'a'+1]; 52 bool flag=1; 53 for (int i=0;i<lt-1;i++) 54 if (!Play(i)) {flag=0;break;} 55 if (flag) 56 { 57 memset(vis,0,sizeof(vis)); 58 for (int i=0;i<ls;i++) 59 { 60 scanf("%d",&x);x--; 61 vis[x]=1; 62 int pos=find(x); 63 if (P[pos]==x) 64 { 65 P[pos]=next[P[pos]]; 66 while (P[pos]!=-1 && vis[P[pos]]) P[pos]=next[P[pos]]; 67 if (P[pos]==-1) break; 68 if (!Play(pos)) break; 69 } 70 ans++; 71 // for (int j=0;j<ls;j++) cout<<vis[j]<<' ';cout<<endl; 72 // for (int j=0;j<lt;j++) cout<<P[j]<<' ';cout<<endl; 73 } 74 } 75 printf("%d ",ans); 76 return 0; 77 }
该代码在随机数据下表现良好,因此如果是oi赛制可以拿到不错的分数。但是理论复杂度是n2的,而且存在aaaa……这样的数据使得t中每个字符都要跳n次。
解法二:
我们要在排列中找一个位置,它左边的都符合某个条件,而右边都不符合。二分!!
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 //#include<iostream> 8 using namespace std; 9 10 #define maxs 200011 11 char s[maxs];int ls; 12 char t[maxs];int lt; 13 int a[maxs]; 14 bool vis[maxs]; 15 int main() 16 { 17 scanf("%s%s",s,t); 18 ls=strlen(s),lt=strlen(t); 19 for (int i=0;i<ls;i++) scanf("%d",&a[i]),a[i]--; 20 int L=0,R=ls-1; 21 while (L<R) 22 { 23 int mid=(L+R+1)>>1; 24 memset(vis,0,sizeof(vis)); 25 for (int i=0;i<mid;i++) vis[a[i]]=1; 26 int j=0; 27 for (int i=0;i<ls;i++) 28 if (j<lt && s[i]==t[j] && !vis[i]) j++; 29 if (j==lt) L=mid; 30 else R=mid-1; 31 } 32 printf("%d ",L); 33 return 0; 34 }