CF778A:String Game

给出字符串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\n",ans);
76     return 0;
77 }
View Code

该代码在随机数据下表现良好,因此如果是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\n",L);
33     return 0;
34 }
View Code

 

posted @ 2017-07-17 11:09  Blue233333  阅读(244)  评论(0编辑  收藏  举报