码迷,mamicode.com
首页 > 其他好文 > 详细

Practice II 字符串

时间:2018-10-10 11:59:57      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:最大值   spl   长度范围   seq   isp   sequence   rac   scanf   scan   

本来想做数论的……但是别的dalao都在做制胡窜

所以……

 

Chapter I KMP

KMP 最关键的不是这个半暴力的单模匹配

而是这个nxt数组 经常出一些奇怪的题 尤其是循环节可以直接由T-nxt[T]得到……神啊

总之记住nxt就是最长公共前后缀中前缀的尾指针就OK

 

T1 poj3461 Oulipo

Time cost: 10min

纯纯的板子 真没啥可说的

就是每次清空nxt就OK

Code:

技术分享图片
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N = 1000005;
 5 #define rep(i,a,n) for(int i = a;i <= n;i++)
 6 #define ms(a,b) memset(a,b,sizeof a)
 7 
 8 char s[N],t[N];
 9 int S,T;
10 int nxt[N];
11 int ans;
12 void clr(){ms(nxt,0),ans = 0;}
13 void gnxt() {
14     int tmp = 0;
15     rep(i,2,T) {
16     while(tmp && t[tmp+1] != t[i]) tmp = nxt[tmp];
17     if(t[tmp+1] == t[i]) nxt[i] = ++tmp;
18     }
19 }
20 void KMP() {
21     int tmp = 0;
22     rep(i,1,S) {
23     while(tmp && t[tmp+1] != s[i]) tmp = nxt[tmp];
24     if(t[tmp+1] == s[i]) {
25         tmp++;
26         if(tmp == T) ans++;
27     }
28     }
29 }
30 
31 
32 int main() {
33     int q;
34     scanf("%d",&q);
35     while(q--) {
36     clr();
37     scanf("%s",t+1),scanf("%s",s+1);
38     S = strlen(s+1),T = strlen(t+1);
39     gnxt();
40     KMP();
41     printf("%d\n",ans);
42     }
43 }
View Code

 

T2 poj 2406 Power strings

Time cost:55min

之前曾经遇到过……最后暴力滚粗

今天算是靠着打表理解了

由于nxt定义的时候刨去了串本身是自己的最长公共前后缀

在最后一次求nxt的时候 我们考虑被nxt[T]抛弃的部分(记为len)

如果这一段能整除T,那么考虑第二段len长的串

它与第一段len长的串是相等的

同理可以推到T/len倍

同时 nxt取最大值 咕T-nxt[T]取最小

所以如果T是T-nxt[T]的整数倍 那么T-nxt[T]就是最小循环节

Code:

技术分享图片
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N = 1000005;
 5 #define rep(i,a,n) for(int i = a;i <= n;i++)
 6 #define ms(a,b) memset(a,b,sizeof a)
 7 
 8 char s[N],t[N];
 9 int S,T;
10 int nxt[N];
11 int ans;
12 void clr(){ms(nxt,0),ans = 0;}
13 void gnxt() {
14     int tmp = 0;
15     rep(i,2,T) {
16     while(tmp && t[tmp+1] != t[i]) tmp = nxt[tmp];
17     if(t[tmp+1] == t[i]) nxt[i] = ++tmp;
18     }
19 }
20 void KMP() {
21     int tmp = 0;
22     rep(i,1,S) {
23     while(tmp && t[tmp+1] != s[i]) tmp = nxt[tmp];
24     if(t[tmp+1] == s[i]) {
25         tmp++;
26         if(tmp == T) ans++;
27     }
28     }
29 }
30 
31 
32 int main() {
33     while(1) {
34     clr();
35     scanf("%s",t+1);
36     T = strlen(t+1);
37     if(T == 1 && t[1] == .) return 0;
38     gnxt();
39     if(T % (T - nxt[T]) == 0) printf("%d\n",T/(T-nxt[T]));
40     else puts("1");
41     }
42 }
View Code

 

T3 CF562D Om Nom and Necklace

Time cost:45min

有了前一道题做铺垫 还是比较容易想到的

交叉没法做 我们视AB为循环节 

由于k给定 所以通过i和k可以求出一个循环节长度范围

如果这个长度是由nxt求出的最短循环节的整数倍就OK

实现的时候是 除len然后判断合法区间是否存在 这样就可以自动减掉后面剩的一段A

但是要注意 A或B为空的情况就是分成k段或者k+1段纯循环节(没有后缀) 可以特判

(实际A为空已经处理过了)

Code:

技术分享图片
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1000005;
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define ms(a,b) memset(a,b,sizeof a)

char s[N],t[N];
int S,T;
int nxt[N];
int ans;
void clr(){ms(nxt,0),ans = 0;}
void gnxt() {
    int tmp = 0;
    rep(i,2,T) {
    while(tmp && t[tmp+1] != t[i]) tmp = nxt[tmp];
    if(t[tmp+1] == t[i]) nxt[i] = ++tmp;
    }
}
void KMP() {
    int tmp = 0;
    rep(i,1,S) {
    while(tmp && t[tmp+1] != s[i]) tmp = nxt[tmp];
    if(t[tmp+1] == s[i]) {
        tmp++;
        if(tmp == T) ans++;
    }
    }
}
int n,k;

int main() {
    scanf("%d%d",&n,&k);
    scanf("%s",t+1);
    T = n;
    gnxt();
    rep(i,1,T) {
    int len = i - nxt[i];
    if(i % (k+1) == 0 && (i / (k+1)) % len == 0) putchar(1);//lenb==0
    else {
        //circular subsequence range
        int upp = i / k,down = i / (k + 1) + 1;
        upp = upp / len;
        down = (down + len - 1) / len;
        if(upp >= down) putchar(1);
        else putchar(0);
    }
    }
    puts("");
    return 0;
}
View Code

To be continued...

Practice II 字符串

标签:最大值   spl   长度范围   seq   isp   sequence   rac   scanf   scan   

原文地址:https://www.cnblogs.com/yuyanjiaB/p/9765150.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!