模板:
struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; bool symbol[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;} int idx(char c) { return c - 'a'; } void insert(char * s) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); symbol[sz] = false; ch[u][c] = sz++; } u = ch[u][c]; } symbol[u] = true;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); if (symbol[fail[r]]) symbol[r] = true; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); // cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); symbol[0] = false; } Matrix build_mat() { Matrix ret = Matrix(sz + 1); for (int i = 0 ; i < sz ; i++) for (int j = 0 ; j < SIGMA_SIZE ; j++) if (symbol[i] == false && !symbol[ch[i][j]]) ret.mat[i][ch[i][j]]++; for (int i = 0 ; i <= sz ; i++) ret.mat[i][sz] = 1; return ret; } }src;
HDU 2222 Keywords Search
找出主串中有多少个模式串出现
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} int ans; const int MAXNNODE = 500010; const int SIGMA_SIZE = 26; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int cnt[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - 'a';} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } cnt[u]++; val[u] = v;//最后的叶子节点给与信息v } //建立字典树 int fail[MAXNNODE],last[MAXNNODE]; int get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { ans += cnt[j]; cnt[j] = 0; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); memset(cnt,false,sizeof(cnt)); } }src; int N; char input[60]; char tag[1000005]; int main() { //freopen("sample.txt","r",stdin); int T; scanf("%d",&T); while (T--) { scanf("%d",&N); gets(input); src.init(); ans = 0; for (int i = 0 ; i < N; i++) { gets(input); src.insert(input,i + 1); } scanf("%s",tag); src.get_fail(); src.Find(tag); printf("%d ",ans); } return 0; }
HDU 2896 病毒侵袭
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 100010; const int SIGMA_SIZE = 130; vector<int>ans; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c;} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v } //建立字典树 int fail[MAXNNODE],last[MAXNNODE]; void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { ans.push_back(val[j]); print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); //memset(cnt,false,sizeof(cnt)); } }src; char tmp[210]; int N,M; char tag[10010]; int main() { //freopen("sample.txt","r",stdin); while (scanf("%d",&N) != EOF) { src.init(); for (int i = 1; i <= N; i++) { scanf("%s",tmp); src.insert(tmp,i); } src.get_fail(); scanf("%d",&M); int ret = 0; for (int i = 1; i <= M; i++) { ans.clear(); scanf("%s",tag); src.Find(tag); if (ans.size() == 0) continue; ret++; printf("web %d:",i); sort(ans.begin(),ans.end()); int k = unique(ans.begin(),ans.end()) - ans.begin(); for (int i = 0 ; i < k ; i++) printf(" %d",ans[i]); putchar(' '); } printf("total: %d ",ret); } return 0; }
HDU 3065 病毒侵袭持续中
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 50010; const int SIGMA_SIZE = 128; int cnt[MAXNNODE]; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - 'A';} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); } }src; char input[1010][60]; char word[2000005]; int N; int main() { while (scanf("%d",&N) != EOF) { memset(cnt,0,sizeof(cnt)); src.init(); for (int i = 1 ; i <= N ; i++) { scanf("%s",input[i]); src.insert(input[i],i); } src.get_fail(); scanf("%s",word); src.Find(word); for (int i = 1 ; i <= N ; i++) { if (cnt[i]) printf("%s: %d ",input[i],cnt[i]); } } return 0; }
ZOJ 3430 Detect the Virus
题意:给出n个编码后的模板串,然后有M次询问,每次询问输入一个编码后的文本串,问在编码前,有多少个模板串在文本串中出现过。
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int SIGMA_SIZE = 256; const int MAXNNODE = 60010; vector<int>ret; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} // int idx(char c) {return c;} void insert(int * s,int n,int v) { int u = 0; for (int i = 0 ; i < n ; i++) { int c = s[i]; if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); ret.push_back(val[j]); print(last[j]); } } void Find(int * T,int n) { int j = 0; for (int i = 0 ; i < n ; i++) { int c = T[i]; // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); } }src; int getid(char ch) { if (isupper(ch)) return ch - 'A'; if (islower(ch)) return ch - 'a' + 26; if (isdigit(ch)) return ch - '0' + 52; if (ch == '+') return 62; return 63; } int str[30010]; char word[30010]; int bit[30010 * 10]; int decode(char * s) { int top = 0,res[10]; int len = strlen(s); for (int i = 0 ; i < len ; i++) { if (s[i] != '=') { int idx = getid(s[i]); for (int j = 5 ; j >= 0 ; j--) { res[j] = idx & 1; idx >>= 1; } for (int j = 0 ; j < 6 ; j++) { bit[top++] = res[j]; } } else top -= 2; } int x = 0,tot = 0; for (int i = 0 ; i < top ;) { x = 0; for (int j = 0 ; j < 8 ; j++) x = x * 2 + bit[i++]; str[tot++] = x; } return tot; } int main() { int N,M; while (scanf("%d",&N) != EOF) { src.init(); for (int i = 1 ; i <= N ; i++) { scanf("%s",word); int length = decode(word); src.insert(str,length,i); } src.get_fail(); scanf("%d",&M); while (M--) { ret.clear(); scanf("%s",word); int length = decode(word); src.Find(str,length); sort(ret.begin(),ret.end()); int cnt = unique(ret.begin(),ret.end()) - ret.begin(); printf("%d ",cnt); } puts(""); } return 0; }
POJ 2778 DNA Sequence
题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。(仅含A,T,C,G四个字符)
复制一下别人的题解
2 1 0 0 1
2 1 1 0 0
1 1 0 1 1
2 1 0 0 1
2 1 0 0 1
M[i,j]表示从结点i到j只走一步有几种走法。
那么M的n次幂就表示从结点i到j走n步有几种走法。
注意:危险结点要去掉,也就是去掉危险结点的行和列。结点3和4是单词结尾所以危险,结点2的fail指针指向4,当匹配”AC”时也就匹配了”C”,所以2也是危险的。
矩阵变成M:
2 1
2 1
计算M[][]的n次幂,然后 Σ(M[0,i]) mod 100000 就是答案。
由于n很大,可以使用二分来计算矩阵的幂
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 150; const int SIGMA_SIZE = 4; const LL MOD = 100000; struct Matrix { LL mat[MAXNNODE][MAXNNODE]; int n; Matrix(){} Matrix(int sz) { n = sz; for (int i = 0 ; i < n ; i++) for (int j = 0 ; j < n ; j++) mat[i][j] = 0; } Matrix operator * (const Matrix &b) const{ Matrix ret = Matrix(n); for (int i = 0 ; i < n ; i++) for (int j = 0 ; j < n ; j++) for (int k = 0 ; k < n ; k++) ret.mat[i][j] = (ret.mat[i][j] + mat[i][k] * b.mat[k][j]) % MOD; return ret; } }; LL pow_mod(LL x,int cnt) { LL ret = 1; while (cnt) { if (cnt & 1) ret = ret * x; x = x * x % MOD; cnt >>= 1; } return ret; } Matrix mat_pow(Matrix in,LL cnt) { Matrix ret = Matrix(in.n); Matrix x = in; for (int i = 0 ; i < ret.n ; i++) ret.mat[i][i] = 1; while (cnt) { if (cnt & 1LL) ret = ret * x; x = x * x; cnt >>= 1LL; } return ret; } struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; bool symbol[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;} int idx(char c) { if (c == 'A') return 0; if (c == 'T') return 1; if (c == 'C') return 2; return 3; } void insert(char * s) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); symbol[sz] = false; ch[u][c] = sz++; } u = ch[u][c]; } symbol[u] = true;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); if (symbol[fail[r]]) symbol[r] = true; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); // cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); symbol[0] = false; } Matrix build_mat() { Matrix ret = Matrix(sz); for (int i = 0 ; i < sz ; i++) for (int j = 0 ; j < SIGMA_SIZE ; j++) if (symbol[i] == false && !symbol[ch[i][j]]) ret.mat[i][ch[i][j]]++; return ret; } }src; int main() { LL M,N; char tmp[20]; while (scanf("%I64d%I64d",&M,&N) != EOF) { src.init(); for (int i = 0 ; i < M ; i++) { scanf("%s",tmp); src.insert(tmp); } src.get_fail(); Matrix cur = src.build_mat(); /* for (int i = 0 ; i < cur.n ; i++){ for (int j = 0 ; j < cur.n ; j++) printf("%I64d ",cur.mat[i][j]); puts(""); }*/ // Matrix ret = cur * cur * cur; Matrix ret = mat_pow(cur,N); /* for (int i = 0 ; i < cur.n ; i++){ for (int j = 0 ; j < cur.n ; j++) printf("%I64d ",ret.mat[i][j]); puts(""); }*/ LL ans = 0; for (int i = 0 ; i < src.sz ; i++) ans = (ans + ret.mat[0][i]) % MOD; printf("%I64d ",ans); } return 0; }
HDU 2243 考研路茫茫――单词情结
这题的意思是,给你n个长度不超过5的字符串,求有多少个长度为至少为L的字符串,里面至少包含n个字符串中的一个。
这题和求DNA片段的差不多啦,只不过L的条件有点变化。
POJ2778 是求长度为n,不包含模式串。
假设矩阵A里储存着字符间的可行转移,那么A^L就代表了长度为L的不包含n个字符串中任何一个的个数。
最终的答案就是26^1+26^2+......+26^L减去A^1+A^2+....+A^L
矩阵A可以用ac自动机维护一个跳转表得到。接下来就是考虑如何快速的求得A^1+A^2+....+A^L了。
根据矩阵的性质
|A , 1| |A^n , 1+A^1+A^2+....+A^(n-1)|
|0 , 1| 的n次方等于|0 , 1|
利用POJ 2778 的方式构建A
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define ULL unsigned long long #define LL unsigned long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 150; const int SIGMA_SIZE = 26; const LL MOD = 100000; struct Matrix { ULL mat[MAXNNODE][MAXNNODE]; int n; Matrix(){} Matrix(int sz) { n = sz; for (int i = 0 ; i < n ; i++) for (int j = 0 ; j < n ; j++) mat[i][j] = 0; } Matrix operator * (const Matrix &b) const{ Matrix ret = Matrix(n); for (int i = 0 ; i < n ; i++) for (int j = 0 ; j < n ; j++) for (int k = 0 ; k < n ; k++) ret.mat[i][j] = (ret.mat[i][j] + mat[i][k] * b.mat[k][j]); return ret; } }; LL pow_mod(LL x,int cnt) { LL ret = 1; while (cnt) { if (cnt & 1) ret = ret * x; x = x * x % MOD; cnt >>= 1; } return ret; } Matrix mat_pow(Matrix in,LL cnt) { Matrix ret = Matrix(in.n); Matrix x = in; for (int i = 0 ; i < ret.n ; i++) ret.mat[i][i] = 1; while (cnt) { if (cnt & 1LL) ret = ret * x; x = x * x; cnt >>= 1LL; } return ret; } struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; bool symbol[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;} int idx(char c) { return c - 'a'; } void insert(char * s) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); symbol[sz] = false; ch[u][c] = sz++; } u = ch[u][c]; } symbol[u] = true;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); if (symbol[fail[r]]) symbol[r] = true; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); // cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); symbol[0] = false; } Matrix build_mat() { Matrix ret = Matrix(sz + 1); for (int i = 0 ; i < sz ; i++) for (int j = 0 ; j < SIGMA_SIZE ; j++) if (symbol[i] == false && !symbol[ch[i][j]]) ret.mat[i][ch[i][j]]++; for (int i = 0 ; i <= sz ; i++) ret.mat[i][sz] = 1; return ret; } }src; int main() { LL M,N; char tmp[20]; while (scanf("%I64d%I64d",&M,&N) != EOF) { src.init(); for (int i = 0 ; i < M ; i++) { scanf("%s",tmp); src.insert(tmp); } src.get_fail(); Matrix cur = src.build_mat(); /* for (int i = 0 ; i < cur.n ; i++){ for (int j = 0 ; j < cur.n ; j++) printf("%I64d ",cur.mat[i][j]); puts(""); }*/ // Matrix ret = cur * cur * cur; Matrix ret = mat_pow(cur,N); /* for (int i = 0 ; i < cur.n ; i++){ for (int j = 0 ; j < cur.n ; j++) printf("%I64d ",ret.mat[i][j]); puts(""); }*/ ULL ans = 0; for (int i = 0 ; i <= src.sz ; i++) ans = (ans + ret.mat[0][i]); ans--; Matrix t = Matrix(2); t.mat[0][0] = 26; t.mat[1][0] = t.mat[1][1] = 1; t = mat_pow(t,N); ULL res = t.mat[0][0] + t.mat[1][0]; // << res << endl; res--; printf("%I64u ",res - ans); } return 0; }
POJ 1625 Censored!
题意:给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} map<char,int>mp; struct Matrix { int mat[110][110]; int n; Matrix(){} Matrix(int sz) { n = sz; for (int i = 0 ; i < n ; i++) for (int j = 0 ; j < n ; j++) mat[i][j] = 0; } }mt; const int numlen = 104; const int MAXNNODE = 130 * 200; const int SIGMA_SIZE = 130; int N,M,P,cas; struct bign { int len, s[numlen]; bign() { memset(s, 0, sizeof(s)); len = 1; } bign(int num) { *this = num; } bign(const char *num) { *this = num; } bign operator = (const int num) { char s[numlen]; sprintf(s, "%d", num); *this = s; return *this; } bign operator = (const char *num) { len = strlen(num); while(len > 1 && num[0] == '0') num++, len--; for(int i = 0;i < len; i++) s[i] = num[len-i-1] - '0'; return *this; } void deal() { while(len > 1 && !s[len-1]) len--; } bign operator + (const bign &a) const { bign ret; ret.len = 0; int top = max(len, a.len) , add = 0; for(int i = 0;add || i < top; i++) { int now = add; if(i < len) now += s[i]; if(i < a.len) now += a.s[i]; ret.s[ret.len++] = now%10; add = now/10; } return ret; } bign operator - (const bign &a) const { bign ret; ret.len = 0; int cal = 0; for(int i = 0;i < len; i++) { int now = s[i] - cal; if(i < a.len) now -= a.s[i]; if(now >= 0) cal = 0; else { cal = 1; now += 10; } ret.s[ret.len++] = now; } ret.deal(); return ret; } bign operator * (const bign &a) const { bign ret; ret.len = len + a.len; for(int i = 0;i < len; i++) { for(int j = 0;j < a.len; j++) ret.s[i+j] += s[i]*a.s[j]; } for(int i = 0;i < ret.len; i++) { ret.s[i+1] += ret.s[i]/10; ret.s[i] %= 10; } ret.deal(); return ret; } bign operator * (const int num) { // printf("num = %d ", num); bign ret; ret.len = 0; int bb = 0; for(int i = 0;i < len; i++) { int now = bb + s[i]*num; ret.s[ret.len++] = now%10; bb = now/10; } while(bb) { ret.s[ret.len++] = bb % 10; bb /= 10; } ret.deal(); return ret; } bign operator / (const bign &a) const { bign ret, cur = 0; ret.len = len; for(int i = len-1;i >= 0; i--) { cur = cur*10; cur.s[0] = s[i]; while(cur >= a) { cur -= a; ret.s[i]++; } } ret.deal(); return ret; } bign operator % (const bign &a) const { bign b = *this / a; return *this - b*a; } bign operator += (const bign &a) { *this = *this + a; return *this; } bign operator -= (const bign &a) { *this = *this - a; return *this; } bign operator *= (const bign &a) { *this = *this * a; return *this; } bign operator /= (const bign &a) { *this = *this / a; return *this; } bign operator %= (const bign &a) { *this = *this % a; return *this; } bool operator < (const bign &a) const { if(len != a.len) return len < a.len; for(int i = len-1;i >= 0; i--) if(s[i] != a.s[i]) return s[i] < a.s[i]; return false; } bool operator > (const bign &a) const { return a < *this; } bool operator <= (const bign &a) const { return !(*this > a); } bool operator >= (const bign &a) const { return !(*this < a); } bool operator == (const bign &a) const { return !(*this > a || *this < a); } bool operator != (const bign &a) const { return *this > a || *this < a; } string str() const { string ret = ""; for(int i = 0;i < len; i++) ret = char(s[i] + '0') + ret; return ret; } }; istream& operator >> (istream &in, bign &x) { string s; in >> s; x = s.c_str(); return in; } ostream& operator << (ostream &out, const bign &x) { out << x.str(); return out; } bign dp[2][110]; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return mp[c];} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); val[r] |= val[fail[r]]; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); //cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); } Matrix build_mat() { Matrix ret = Matrix(sz); for (int i = 0 ; i < sz ; i++) { for (int j = 0 ; j < N ; j++) if (val[ch[i][j]] == false) ret.mat[i][ch[i][j]]++; } return ret; } void slove() { int cur = 0; dp[cur][0] = 1; for (int i = 1 ; i < sz ; i++) dp[cur][i] = 0; for (int i = 0 ; i < M ; i++) { cur ^= 1; for (int j = 0 ; j < sz ; j++) dp[cur][j] = 0; for (int j = 0 ; j < sz ; j++) { for (int k = 0 ; k < sz ; k++) if (mt.mat[j][k] > 0) dp[cur][k] = dp[cur][k] + dp[cur ^ 1][j] * mt.mat[j][k]; } } bign ret = "0"; for (int i = 0 ; i < sz ; i++) ret = ret + dp[cur][i]; cout << ret << endl; } }src; char str[100]; int main() { // freopen("sample.txt","r",stdin); while (scanf("%d%d%d",&N,&M,&P) != EOF) { mp.clear(); gets(str); cas = 0; gets(str); int len = strlen(str); for (int i = 0 ; i < len ; i++) mp[str[i]] = cas++; src.init(); for (int i = 0 ; i < P; i++) { gets(str); src.insert(str,1); } src.get_fail(); mt = src.build_mat(); src.slove(); } return 0; }
HDU 2825 Wireless Password
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 110; const int SIGMA_SIZE = 26; const int MOD = 20090717; int N,M,K; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int dp[2][MAXNNODE][1 << 10]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - 'a';} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v } //建立字典树 int fail[MAXNNODE],last[MAXNNODE]; void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); val[r] |= val[fail[r]]; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; // val[u] |= val[fail[u]]; } } } void print(int j) { if (j) { print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); // memset(cnt,false,sizeof(cnt)); } int calcu(int n,int sta,int num) { memset(dp[0],0,sizeof(dp[0])); int cur = 0,nxt; dp[0][0][0] = 1; while (n--) { nxt = 1 - cur; memset(dp[nxt],0,sizeof(dp[nxt])); for (int i = 0 ; i < sz ; i++) for (int j = 0 ; j < sta ; j++) { if (dp[cur][i][j] == 0) continue; for (int k = 0 ; k < SIGMA_SIZE ; k++) { int tmp = ch[i][k]; int nextsta = (j | (val[tmp])); dp[nxt][tmp][nextsta] = (dp[nxt][tmp][nextsta] + dp[cur][i][j]) % MOD; } } cur = nxt; } int ret = 0; for (int j = 0 ; j < sta ; j++) { int cnt = 0; for (int i = 0 ; i < N; i++) if (j & (1 << i)) cnt++; if (cnt >= K) { for (int t = 0 ; t < sz ; t++) ret = (ret + dp[cur][t][j]) % MOD; } } return ret; } }src; int main() { //freopen("sample.txt","r",stdin); while (scanf("%d%d%d",&N,&M,&K) != EOF) { if (N == 0 && M == 0 && K == 0) break; src.init(); for (int i = 0 ; i < M; i++) { char tmp[20]; scanf("%s",tmp); src.insert(tmp,1 << i); } src.get_fail(); printf("%d ",src.calcu(N,1 << M,K)); } return 0; }
HDU 2296 Ring
题目:给出m个模式串,每个串有一定的分值,构造一个长度不超过n的串,使得分值最大,输出长度最小,字典序最小的串
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 using namespace std; int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);} const int MAXNNODE = 1110; const int SIGMA_SIZE = 26; const int INF = 0x3f3f3f3f; int N,M; int h[MAXNNODE]; char res[60][MAXNNODE][60]; bool cmp(char * s,char * t) { int len1 = strlen(s); int len2 = strlen(t); if (len1 != len2) return len1 < len2; return strcmp(s,t) < 0; } struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int sz; LL dp[60][MAXNNODE]; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - 'a';} void insert(char * s,int v) { int u = 0,n = strlen(s); for (int i = 0 ; i < n ; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v;//最后的叶子节点给与信息v // printf("%d %d ",u,v); } //建立字典树 void get_fail() { queue<int>q; fail[0] = 0; for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[0][c]; if (u) { fail[u] = 0; q.push(u); last[u] = 0; } } while (!q.empty()) { int r = q.front();q.pop(); for (int c = 0 ; c < SIGMA_SIZE ; c++) { int u = ch[r][c]; if (u == 0) { ch[r][c] = ch[fail[r]][c]; continue; } q.push(u); int v = fail[r]; while (v && !ch[v][c]) v = fail[v]; fail[u] = ch[v][c]; last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; } } } void print(int j) { if (j) { // printf("%d ",val[j]); // cnt[val[j]]++; print(last[j]); } } void Find(char * T) { int n = strlen(T); int j = 0; for (int i = 0 ; i < n ; i++) { int c = idx(T[i]); // while(j && !ch[j][c]) j = f[j]; j = ch[j][c]; if (val[j]) print(j); else if (last[j]) print(last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); } void calcu() { for (int i = 0 ; i <= N ; i++) for (int j = 0 ; j < sz ; j++) dp[i][j] = -INF; dp[0][0] = 0; strcpy(res[0][0],""); char ret[60]; strcpy(ret,""); int MAX = 0; char tmp[60]; for (int i = 0 ; i < N ; i++) { for (int j = 0 ; j < sz ; j++) { if (dp[i][j] < 0) continue; strcpy(tmp,res[i][j]); int len = strlen(tmp); for (int k = 0 ; k < SIGMA_SIZE ; k++) { int nxt = ch[j][k]; tmp[len] = k + 'a'; tmp[len + 1] = '