CodeForces 536B Tavas and Malekas :构造长为n的串,使m个串的开头是给定的某个字符串,求构造方案数 kmp/hash...

本题的难点在于--->看懂题意

因为比赛纠结于A的二分,比赛还没结束就暴走睡觉了TUT今天起来看了看B===卧槽题意和A一样恶心啊有木有==

回到本题,看明白之后首先映入眼前的就是--->暴力大法好

这样必然是可以hack超时的,必须要对串进行处理哪些后缀和前缀相等

最常规的莫过于kmp里面的next,从结尾一直next找找找到找不到,那些地方表示和后缀相同,这个和之前做过的hdu某题类似

这是用kmp写的本题代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 #define LL long long
 6 #define MOD 1000000007
 7 LL vis[1000005],f[1000005],Next[1000005];
 8 char s[1000005];
 9 void getnext(char *B,LL m){
10   LL i,j;
11   Next[1]=j=0;
12   for (i=2;i<=m;i++){
13     while (j>0&&B[j+1]!=B[i]) j=Next[j];
14     if (B[j+1]==B[i]) j++;
15     Next[i]=j;
16   }
17   i=m;
18   while (Next[i]){
19     i=Next[i];
20     f[i]=1;
21   }
22 }
23 int main()
24 {
25   LL n,m,len,ans,pre,cnt,i,x,tmp;
26   scanf("%I64d%I64d",&n,&m);
27   scanf("%s",s+1);
28   len=strlen(s+1); 
29   memset(vis,0,sizeof(vis));
30   memset(f,0,sizeof(f));
31   for (i=1;i<=m;i++){
32     scanf("%I64d",&x);
33     vis[x]=1;
34   }
35   getnext(s,len);
36 //  for (i=1;i<=len;i++) printf("%I64d",f[i]); printf("\n");
37   cnt=pre=0;
38   for (i=1;i<=n;i++){
39     if (vis[i]){
40       if (pre&&pre+len>i){
41         tmp=len-(i-pre);
42         if (f[tmp]!=1){
43           printf("0\n");
44           return 0;
45         }
46       }
47       pre=i;
48     }
49     if (pre==0||pre+len<=i) cnt++;
50   }
51   ans=1;
52   for (i=1;i<=cnt;i++) ans=ans*26%MOD;
53   printf("%I64d\n",ans);
54   return 0;
55 }
View Code

当然,判断两个字符串的另外一种方法hash黑科技也可以,听说单hash容易被卡,交了几发都过了,上一个双hash的==

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 #define LL long long
 6 #define MOD 1000000007
 7 struct Hash{
 8   LL B,mod,len,Has[1000005],Base[1000005];
 9   void init(char *s,LL _len,LL _B,LL _mod){
10     B=_B; mod=_mod; len=_len;
11     Base[0]=1; Has[0]=0; 
12     for (LL i=1;i<=len;i++){
13       Base[i]=Base[i-1]*B%mod;
14       Has[i]=(Has[i-1]*B+s[i-1]-'a'+1)%mod;
15     }
16     return;
17   }
18   LL gethash(LL l,LL r){
19     return ((Has[r]-Has[l-1]*Base[r-l+1])%mod+mod)%mod;
20   }
21 };
22 LL vis[1000005];
23 char s[1000005];
24 Hash H1,H2;
25 int main()
26 {
27   LL n,m,len,ans,pre,cnt,i,x,tmp;
28   scanf("%I64d%I64d",&n,&m);
29   scanf("%s",s);
30   len=strlen(s); 
31   H1.init(s,len,171,MOD);
32   H2.init(s,len,191,MOD+2);
33   memset(vis,0,sizeof(vis));
34   for (i=1;i<=m;i++){
35     scanf("%I64d",&x);
36     vis[x]=1;
37   }
38   cnt=pre=0;
39   for (i=1;i<=n;i++){
40     if (vis[i]){
41       if (pre&&pre+len>i){
42         tmp=len-(i-pre);
43         if (H1.gethash(1,tmp)!=H1.gethash(len-tmp+1,len)
44           ||H2.gethash(1,tmp)!=H2.gethash(len-tmp+1,len)){
45           printf("0\n");
46           return 0;
47         }
48       }
49       pre=i;
50     }
51     if (pre==0||pre+len<=i) cnt++;
52   }
53   ans=1;
54   for (i=1;i<=cnt;i++) ans=ans*26%MOD;
55   printf("%I64d\n",ans);
56   return 0;
57 }
View Code

题目链接:http://codeforces.com/contest/536/problem/B

转载于:https://www.cnblogs.com/xiao-xin/articles/4429338.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值