• BZOJ2099: [Usaco2010 Dec]Letter 恐吓信


    给两个长度不超过50000的串,A串可每次截连续一段复制出来,求最少复制几次能得到B串。

    方法一:SAM。不会。

    嗯好会了。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdlib.h>
     5 //#include<iostream>
     6 //#include<time.h>
     7 using namespace std;
     8 
     9 int n,m;
    10 #define maxn 200011*2
    11 char s[maxn],p[maxn];
    12 struct SAM
    13 {
    14     int ch[maxn][26],size,last,pre[maxn],pos[maxn];
    15     SAM()
    16     {
    17         size=0;
    18         memset(ch[0],0,sizeof(ch[0]));
    19         pre[0]=-1;
    20     }
    21     int idx(char c) {return c-'A';}
    22     void insert(char c,int p)
    23     {
    24         int id=idx(c),x=++size;
    25         memset(ch[x],0,sizeof(ch[x])); pos[x]=p;
    26         int y=last;
    27         for (;y!=-1 && !ch[y][id];y=pre[y]) ch[y][id]=x;
    28         last=x;
    29         if (y==-1) pre[x]=0;
    30         else
    31         {
    32             if (pos[ch[y][id]]==pos[y]+1) pre[x]=ch[y][id];
    33             else
    34             {
    35                 int z=ch[y][id],w=++size;
    36                 memcpy(ch[w],ch[z],sizeof(ch[z]));
    37                 pos[w]=pos[y]+1; pre[w]=pre[z];
    38                 pre[z]=pre[x]=w;
    39                 for (;y!=-1 && ch[y][id]==z;y=pre[y]) ch[y][id]=w;
    40             }
    41         }
    42     }
    43 }sam;
    44 
    45 int main()
    46 {
    47     scanf("%d%d",&n,&m);
    48     for (int i=1;i<=n;i++)
    49     {
    50         char c;while (!((c=getchar())>='A' && c<='Z'));
    51         sam.insert(c,i);
    52     }
    53     for (int i=1;i<=m;i++) while (!((p[i]=getchar())>='A' && p[i]<='Z'));
    54     int pos=1,ans=0;
    55     while (pos<=m)
    56     {
    57         int now=0;
    58         while (pos<=m && sam.ch[now][p[pos]-'A']) now=sam.ch[now][p[pos]-'A'],pos++;
    59 //        cout<<endl;
    60         ans++;
    61     }
    62     printf("%d
    ",ans);
    63     return 0;
    64 }
    View Code

    方法二:其实就是拿B去A上面匹配若干次。多次匹配的话可以把A先建个后缀数组,然后每次二分到B的位置搞匹配。匹配一次怕太慢的话,用hash吧!二分匹配长度找到第一个不可匹配的位置,就可以算匹配长度啦!

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stdlib.h>
      4 #include<algorithm>
      5 //#include<iostream>
      6 using namespace std;
      7 
      8 int n,m;
      9 #define maxn 50011
     10 char t[maxn],p[maxn],c;
     11 int ht[maxn],hp[maxn];
     12 int sa[maxn],cnt[maxn],rank[maxn],y[maxn];
     13 void makesa(char* s)
     14 {
     15     int n=strlen(s),m=26;
     16     for (int i=0;i<m;i++) cnt[i]=0;
     17     for (int i=0;i<n;i++) cnt[rank[i]=s[i]-'A']++;
     18     for (int i=1;i<m;i++) cnt[i]+=cnt[i-1];
     19     for (int i=n-1;i>=0;i--) sa[--cnt[rank[i]]]=i;
     20     for (int k=1;k<=n;k<<=1)
     21     {
     22         int p=0;
     23         for (int i=n-k;i<n;i++) y[p++]=i;
     24         for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
     25         for (int i=0;i<m;i++) cnt[i]=0;
     26         for (int i=0;i<n;i++) cnt[rank[y[i]]]++;
     27         for (int i=1;i<m;i++) cnt[i]+=cnt[i-1];
     28         for (int i=n-1;i>=0;i--) sa[--cnt[rank[y[i]]]]=y[i];
     29         memcpy(y,rank,sizeof(y));
     30         p=0;rank[sa[0]]=0;
     31         for (int i=1;i<n;i++)
     32             rank[sa[i]]=y[sa[i]]==y[sa[i-1]] && ((sa[i]+k>=n && sa[i-1]+k>=n)
     33             || (sa[i]+k<n && sa[i-1]+k<n && y[sa[i]+k]==y[sa[i-1]+k]))?p:++p;
     34         if (p==n-1) break;
     35         m=p+1;
     36     }
     37 }
     38 void makeh(char* s,int* h)
     39 {
     40     int n=strlen(s);
     41     h[0]=s[0]-'A';
     42     for (int i=1;i<n;i++)
     43         h[i]=h[i-1]*27+s[i]-'A';
     44 }
     45 int pw[maxn];
     46 void makepw(int n)
     47 {
     48     pw[0]=1;
     49     for (int i=1;i<=n;i++)
     50         pw[i]=pw[i-1]*27;
     51 }
     52 bool ok(int x,int y)
     53 {
     54     int L=0,R=min(n-x,m-y);
     55     while (L<R)
     56     {
     57         if (ht[x+mid-1]-ht[x-1]*pw[mid]==hp[y+mid-1]-hp[y-1]*pw[mid]) L=mid;
     58         else R=mid-1;
     59     }
     60     return p[y+L]<=t[x+L];
     61 }
     62 int lcp(int x,int y)
     63 {
     64     int now=0;
     65     while (x<n && y<m && t[x]==p[y]) now++,x++,y++;
     66     return now;
     67 }
     68 void play(int &x)
     69 {
     70     int L=0,R=n;
     71     while (L<R)
     72     {
     73         int mid=(L+R)>>1;
     74         if (ok(sa[mid],x)) R=mid;
     75         else L=mid+1;
     76     }
     77     if (!L) x+=lcp(sa[L],x);
     78     else if (L<n) x+=max(lcp(sa[L-1],x),lcp(sa[L],x));
     79     else x+=lcp(sa[n-1],x);
     80 }
     81 bool isalpha(char c) {return c>='A' && c<='Z';}
     82 int main()
     83 {
     84     scanf("%d%d",&n,&m);
     85     t[n]='';p[m]='';
     86     for (int i=0;i<n;i++)
     87     {
     88         while (!isalpha(c=getchar()));
     89         t[i]=c;
     90     }
     91     for (int i=0;i<m;i++)
     92     {
     93         while (!isalpha(c=getchar()));
     94         p[i]=c;
     95     }
     96     makesa(t);
     97     makeh(t,ht);makeh(p,hp);makepw(max(n,m));
     98     int now=0,ans=0;
     99     while (now<m) play(now),ans++;
    100     printf("%d
    ",ans);
    101     return 0;
    102 }
    View Code
  • 相关阅读:
    Python 集合
    Python 文字列
    JUNIT5(maven配置)
    Javascript严格模式
    移动互联测试
    Python的基础知识
    Linux系统下发件oa环境
    禅道的使用
    Linux系统的安装过程
    Oracle基础知识
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7541320.html
Copyright © 2020-2023  润新知