• 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
    ",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
    ",L);
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    Object转bigdecimal
    如何在A用户下建立视图,这个视图是A的表与B的表进行关联的?
    java.util.Date和java.sql.Date的区别和相互转化(转)
    JAVA如何获取GUID
    详解Oracle DELETE和TRUNCATE 的区别(摘)
    分开显示Excel2010打开的文档
    CentOS实验三:使用安装光盘建立本地软件源
    基本C库函数
    Shell_2(验证符合的输入)
    Shell_1(目录之间切换执行脚本)
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7193359.html
Copyright © 2020-2023  润新知