仅为自用,不作推广html
一块儿来看猫片吧!ios
一篇不错的博客,然而我闷了一下午仍是不会,看了看书算是搞懂了git
博客里面各类性质讲的很是详细,有空能够回看一下数组
核心的两段代码spa
nxt数组预处理:.net
我这里使用pre表示nxt数组,用go表示要匹配的串指针
void init(){//预处理pre数组 int len = strlen(go + 1); int j = 0; for(int i = 1; i < len; ++i){ while(j > 0 && go[i + 1] != go[j + 1]) j = pre[j]; if(go[i + 1] == go[j + 1]) ++j; pre[i + 1] = j; } }
原字符串的匹配:code
for(int i = 0; i < len1; ++i){ while(j > 0 && s[i + 1] != go[j + 1]) j = pre[j]; if(s[i + 1] == go[j + 1]) ++j; // cout<<"i:"<<i<<" "<<j<<endl; if(j == len2){//若是匹配完成 cnt++; j = 0; } }
直接KMP匹配便可,匹配成功将匹配串的指针置为0htm
一个结论题,答案为 \(n - nxt[n]\),好像与nxt数组自己的性质有关blog
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 1e6+6; const int INF = 1; const int mod = 1; int n; LL ans = 0; char s[MAXN]; int pre[MAXN]; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void init(){ int j = 0; for(int i = 1; i <= n; ++i){ while(j > 0 && s[i + 1] != s[j + 1]) j = pre[j]; if(s[i + 1] == s[j + 1]) ++j; pre[i + 1] = j; } } int main() { n = read(); cin >> (s + 1); init(); for(int i = 1; i <= n; ++i){ int j = i; while(pre[j]) j = pre[j]; if(pre[i]) pre[i] = j; ans += (i - j); } printf("%lld", ans); return 0; }
看这位大佬的题解
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 2e4+6; const int INF = 1; const int mod = 1; int n, k, cnt = 0; char s[MAXN]; int pre[MAXN]; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void Kmp(int l){ int j = l - 1; pre[l] = pre[l - 1] = j; for(int i = l; i < n; ++i){ while(j > l - 1 && s[j + 1] != s[i + 1]) j = pre[j]; if(s[j + 1] == s[i + 1]) j++; pre[i + 1] = j; } for(int i = l; i < n; ++i){ j = pre[i + 1]; while(j > l - 1 && l + 2 * (j - l + 1) > i + 1) j = pre[j]; if(j - l + 1 >= k) cnt++; } } int main() { cin >> (s + 1); k = read(); n = strlen(s + 1); for(int i = 1; i <= n; ++i) Kmp(i); printf("%d", cnt); return 0; }
主要思路是开一个栈,来储存还未被消去的字符串
若是一个串匹配完成,从弹出相应的串
在入栈是顺便记录入栈字符的失陪位置,匹配完一个串后能够直接从栈顶所对字符的失陪位置开始匹配
从前到后跑一遍便可,复杂度 \(O(n)\)
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 1e6+6; const int INF = 1; const int mod = 1; char s[MAXN], t[MAXN]; int lens, lent; int pre[MAXN], f[MAXN]; int stc[MAXN], sc = 0; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void init(){ int j = 0; for(int i = 1; i <= lent; ++i){ while(j && t[i + 1] != t[j + 1]) j = pre[j]; if(t[i + 1] == t[j + 1]) ++j; pre[i + 1] = j; } } int main() { cin >> (s + 1); cin >> (t + 1); lens = strlen(s + 1); lent = strlen(t + 1); init(); for(int i = 0, j = 0; i < lens; ++i){ while(j && s[i + 1] != t[j + 1]) j = pre[j]; if(s[i + 1] == t[j + 1]) ++j; f[i + 1] = j; stc[++sc] = i + 1; if(j == lent){ sc -= lent, j = f[stc[sc]]; } } for(int i = 1; i <= sc; i++){ printf("%c", s[stc[i]]); } return 0; }