BZOJ2099: [Usaco2010 Dec]Letter 恐吓信

Posted Blue233333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2099: [Usaco2010 Dec]Letter 恐吓信相关的知识,希望对你有一定的参考价值。

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

方法一:SAM。不会。

方法二:其实就是拿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]=\0;p[m]=\0;
 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\n",ans);
101     return 0;
102 }
View Code

 

以上是关于BZOJ2099: [Usaco2010 Dec]Letter 恐吓信的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ——2101: [Usaco2010 Dec]Treasure Chest 藏宝箱

BZOJ2097[Usaco2010 Dec] 奶牛健美操

BZOJ 2100: [Usaco2010 Dec]Apple Delivery

bzoj 2100: [Usaco2010 Dec]Apple Deliveryspfa

[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分

bzoj2097[Usaco2010 Dec]Exercise 奶牛健美操 二分+贪心