Hdu--4333(扩展KMP)

2014-12-17 01:34:48

思路:仔细思考,发现如果用扩展KMP,求出每个位置到末尾的最大前缀匹配长度,比如1~100,位置50能匹配到75,那么当我们把50~100移动到开头。前25个字符是一样的,需要比较的是第26个字符(也就是移动前的第76个字符),所以如果设next[i]为位置 i 到末尾的最大前缀匹配长度,需要比较的就是s[i + next[i]]与s[next[i]],我们发现如果i + next[i] < len,那么s[i + next[i]] 与 s[next[i]]必然不同,但如果i + next[i] == len,则需要不断地比较i + next[i] 与 next[i]、i + next[i] + 1 与 next[i] + 1。。。。知道找到不同,这显然效率不够。我们可以把原先的串先复制一倍长度,这样就可以把“不断比较的过程省去”。

  如果next[i] >= len,说明移动后相等,如果s[i + next[i]] > s[next[i]] 说明移动后数更大,如果s[i + next[i]] < s[next[i]] 说明移动后数更小 、

  最后还要注意:题目中说数字不能重复,所以要用KMP求出最大循环节,以去重(具体求最大循环节方法见代码)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 using namespace std;
 6 const int maxn = 200010;
 7 
 8 int T,len,ans1,ans2,ans3;
 9 int next[maxn],P[maxn];
10 char s[maxn];
11 
12 void Get_P(){
13     P[0] = -1;
14     int j = -1;
15     for(int i = 1; i < len; ++i){
16         while(j > -1 && s[j + 1] != s[i]) j = P[j];
17         if(s[j + 1] == s[i]) j++;
18         P[i] = j;
19     }
20 }
21 
22 void Ex_kmp(){
23     int k = 0,j,p,L;
24     next[0] = len;
25     while(k < len - 1 && s[k + 1] == s[k]) k++;
26     next[1] = k;
27     k = 1;
28     int top = len / 2;
29     for(int i = 2; i < top; ++i){
30         p = k + next[k] - 1,L = next[i - k];
31         if(i + L > p){
32             j = p - i + 1;
33             if(j < 0) j = 0;
34             while(i + j < len && s[i + j] == s[j]) j++;
35             next[k = i] = j;
36         }
37         else next[i] = L;
38     }
39 }
40 
41 int main(){
42     scanf("%d",&T);
43     for(int tt = 1; tt <= T; ++tt){
44         scanf("%s",s);
45         len = strlen(s);
46         Get_P();
47         int t = len - P[len - 1] - 1;
48         len = t + len % t; //用KMP求最大循环节
49         for(int i = 0; i < len; ++i) s[i + len] = s[i];
50         len *= 2;
51         Ex_kmp();
52         int top = len / 2;
53         ans1 = ans2 = ans3 = 0;
54         for(int i = 0; i < top; ++i){
55             if(next[i] >= len / 2) ans2++;
56             else if(s[i + next[i]] > s[next[i]]) ans3++;
57             else ans1++;
58         }
59         printf("Case %d: %d %d %d\n",tt,ans1,ans2,ans3);
60     }
61     return 0;
62 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4169900.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值