Kuangbin带你飞 AC自动机
模板:
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\n",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\n",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('\n'); } printf("total: %d\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n", 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\n",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\n",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\n",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\n",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] = '\0'; //len++; int value = dp[i][j]; if (val[nxt]) value += h[val[nxt]]; // if (value != 0) printf("%s %d\n",tmp); if (dp[i + 1][nxt] < value || (dp[i + 1][nxt] == value && cmp(tmp,res[i + 1][nxt]))) { dp[i + 1][nxt] = value; strcpy(res[i + 1][nxt],tmp); if (value > MAX || (value == MAX && cmp(tmp,ret))) { MAX = value; strcpy(ret,tmp); } } } } } // printf("%d\n",MAX); printf("%s\n",ret); } }src; int main() { int T; char buf[60]; scanf("%d",&T); while (T--) { scanf("%d%d",&N,&M); src.init(); for (int i = 0 ; i < M ; i++) { scanf("%s",buf); src.insert(buf,i + 1); } for (int i = 1 ; i <= M ; i++) scanf("%d",&h[i]); src.get_fail(); src.calcu(); } return 0; }
题目:给出一些不合法的模式DNA串,给出一个原串,问最少需要修改多少个字符,使得原串中不包含非法串
#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 = 1100; const int SIGMA_SIZE = 4; 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) { if (c == 'A') return 0; if (c == 'G') return 1; if (c == 'C') return 2; if (c == 'T') return 3; } 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; 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 (val[fail[r]]) val[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\n",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; int dp[1110][1100]; int N; char str[1010]; int main() { // freopen("sample.txt","r",stdin); int kase = 1; while (scanf("%d",&N) != EOF) { if (N == 0) break; src.init(); memset(dp,-1,sizeof(dp)); for (int i = 0 ; i < N; i++) { scanf("%s",str); src.insert(str,1); } src.get_fail(); scanf("%s",str + 1); int len = strlen(str + 1); dp[0][0] = 0; for (int i = 0 ; i < len ; i++) { for (int j = 0 ; j < src.sz ; j++) { if (dp[i][j] == -1) continue; int idx = src.idx(str[i + 1]); for (int k = 0 ; k < 4 ; k++) { int add = 0; if (k != idx) add = 1; if (src.val[src.ch[j][k]]) continue; if (dp[i + 1][src.ch[j][k]] == -1) dp[i + 1][src.ch[j][k]] = dp[i][j] + add; else dp[i + 1][src.ch[j][k]] = min(dp[i + 1][src.ch[j][k]],dp[i][j] + add); } } } int ret = INT_MAX; for (int i = 0 ; i < src.sz ; i++) { if (dp[len][i] == -1) continue; ret = min(ret,dp[len][i]); } printf("Case %d: %d\n",kase++,ret == INT_MAX ? -1 : ret); } return 0; }
ZOJ 3228 Searching the String
计算可重叠不可重叠字串出现在主串的次数
可重叠就是裸地AC自动机。
不可重叠,记录字典树上每个点的深度,没匹配到一个模式串,记录一下位置,
#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 = 600010; const int SIGMA_SIZE = 26; const int INF = 0x3f3f3f3f; int pos[MAXNNODE / 6],N; char str[MAXNNODE / 6]; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int depth[MAXNNODE],pre[MAXNNODE]; int cnt[MAXNNODE][2]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - 'a';} int 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; depth[sz] = i + 1; ch[u][c] = sz++; } u = ch[u][c]; } val[u] += v;//最后的叶子节点给与信息v return u; } //建立字典树 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 i,int j) { if (j) { // printf("%d\n",val[j]); cnt[j][0]++; if (i - pre[j] >= depth[j]) { cnt[j][1]++; pre[j] = i; } print(i,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(i,j); else if (last[j]) print(i,last[j]);//print是功能函数 } } void init() { sz = 1; memset(ch[0],0,sizeof(ch[0])); memset(pre,-1,sizeof(pre)); memset(cnt,0,sizeof(cnt)); memset(val,0,sizeof(val)); } }src; int flag[MAXNNODE / 6]; int main() { int kase = 1; while (scanf("%s",str) != EOF) { scanf("%d",&N); src.init(); for (int i = 0 ; i < N ; i++) { char tmp[10]; scanf("%d%s",&flag[i],tmp); pos[i] = src.insert(tmp,1); } src.get_fail(); src.Find(str); printf("Case %d\n",kase++); for (int i = 0 ; i < N ; i++) printf("%d\n",src.cnt[pos[i]][flag[i]]); puts(""); } return 0; }
HDU 3247 Resource Archiver
题目:给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒
问最小的长度为多少
所有的资源串和病毒串都放在Trie树里建立起来,当然作上相应的标记。然后建立fail指针之后
从资源串的结尾出发,BFS,记录能到达其它资源串结尾的步数。得到所有资源串结尾状态的距离邻接阵。
之后是状态压缩DP
#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 = 60010; const int SIGMA_SIZE = 2; const int INF = 0x3f3f3f3f; int pos[12]; struct Ac_Automation { int ch[MAXNNODE][SIGMA_SIZE]; int val[MAXNNODE]; int state[MAXNNODE]; int fail[MAXNNODE],last[MAXNNODE]; int sz; Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {if (c == '0') return 0 ; return 1;} void insert(char * s,bool v,int id = -1) { 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; state[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } if (!v) { pos[id] = u; state[u] |= (1 << id); //printf("%d %d\n",u,state[u]); } val[u] = 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]]; //use in dp problem state[r] |= state[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\n",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])); memset(val,0,sizeof(val)); memset(state,0,sizeof(state)); } }src; int dist[12][MAXNNODE]; char str[1010]; int length[20]; int dp[12][2000]; void bfs(int id,int st) { //printf("%d %d\n",id,st); for (int i = 0 ; i < src.sz ; i++) dist[id][i] = INF; dist[id][st] = 0; queue<int>q; q.push(st); while (!q.empty()) { int u = q.front(); q.pop(); int v = src.ch[u][0]; if (!src.val[v] && dist[id][v] == INF) { dist[id][v] = dist[id][u] + 1;; q.push(v); } v = src.ch[u][1]; if (!src.val[v] && dist[id][v] == INF) { dist[id][v] = dist[id][u] + 1; q.push(v); } } } void calcu(int n) { int limit = (1 << n); for (int i = 0 ; i <= n ; i++) for (int j = 0 ; j < limit ; j++) dp[i][j] = INF; for (int i = 0 ; i < n ; i++) dp[i][1 << i] = length[i]; for (int i = 0 ; i < limit ; i++) { for (int j = 0 ; j < n ; j++) { if ((i & (1 << j)) && dp[j][i] != INF) { for (int k = 0 ; k < n ; k++) { int nxt = i | src.state[pos[k]]; dp[k][nxt] = min(dp[k][nxt],dp[j][i] + dist[j][pos[k]]); } } } } int ret = INF; for (int i = 0 ; i < n ; i++) ret = min(ret,dp[i][limit - 1]); printf("%d\n",ret); } int main() { int N,M; while (scanf("%d%d",&N,&M) != EOF) { if (N == 0 && M == 0) break; src.init(); memset(length,0,sizeof(length)); for (int i = 0 ; i < N ; i++) { scanf("%s",str); length[i] = strlen(str); src.insert(str,false,i); } for (int i = 0 ; i < M ; i++) { scanf("%s",str); src.insert(str,true); } src.get_fail(); // printf("%d\n",src.sz); // for (int i = 0 ; i < 9 ; i++)printf("%d %d\n",i,src.val[i]); for (int i = 0 ; i < N ; i++) bfs(i,pos[i]); calcu(N); } return 0; }
ZOJ 3494 BCD CODE
题目:给出一些模式串,给出一个范围[A,B],求出区间内有多少个数,写成BCD之后,不包含模式串
使用AC自动机,得到bcd[i][j]表示状态i,加了数字j以后到达的状态,为-1表示不能转移
然后就是数位DP了
#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 = 2010; const int SIGMA_SIZE = 2; 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 - '0';} 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(); if (val[fail[r]]) val[r] = 1; //val[r] += val[fail[r]]; use in dp problem 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\n",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])); memset(val,0,sizeof(val)); } }src; int bcd[MAXNNODE][20]; int trans(int pre,int num) { if (src.val[pre]) return -1; int cur = pre; for (int i = 3 ; i >= 0 ; i--) { if (src.val[src.ch[cur][(num >> i) & 1]]) return -1; cur = src.ch[cur][(num >> i) & 1]; } return cur; } void init() { for (int i = 0 ; i < src.sz ; i++) for (int j = 0 ; j < 10 ; j++) bcd[i][j] = trans(i,j); } const int MOD = 1000000009; LL dp[210][MAXNNODE]; int digit[210]; LL dfs(int length,int s,bool ismax,bool zero) { if (length == 0) return 1; if (!ismax && dp[length][s] >= 0) return dp[length][s]; LL ans = 0; if (length > 1 && zero) { ans += dfs(length - 1,s,ismax && digit[length] == 0,true); ans %= MOD; } else { if (bcd[s][0] != -1) { ans += dfs(length - 1,bcd[s][0],ismax && digit[length] == 0,false); ans %= MOD; } } int limit = ismax ? digit[length] : 9; for (int i = 1 ; i <= limit ; i++) { if (bcd[s][i] != -1) { ans += dfs(length - 1,bcd[s][i],ismax && i == limit ,false); ans %= MOD; } } if (!ismax && !zero) dp[length][s] = ans; return ans; } LL calcu(char * s) { int len = strlen(s + 1); for (int i = 1,j = len ; i <= len ; i++,j--) digit[j] = s[i] - '0'; // for (int j = 1 ; j <= len ; j++) printf("%d ",digit[j]); puts(""); return dfs(len,0,true,true); } char str[210]; int main() { int T; scanf("%d",&T); while (T--) { int n; src.init(); scanf("%d",&n); for (int i = 0 ; i < n ; i++) { scanf("%s",str); src.insert(str,1); } src.get_fail(); init(); memset(dp,-1,sizeof(dp)); LL ans = 0; scanf("%s",str + 1); int len = strlen(str + 1); for (int i = len ; i >= 1 ; i--) { if (str[i] > '0') { str[i]--; break; } else str[i] = '9'; } ans -= calcu(str); ans %= MOD; //cout << calcu(str) << endl; scanf("%s",str + 1); // cout << calcu(str) << endl; ans += calcu(str); ans %= MOD; if (ans < 0) ans += MOD; printf("%lld\n",ans); } return 0; }
HDU 4758 Walk Through Squares
题意:给n*m的地图,在地图的点上走,(n+1)*(m+1)个点,两种操作:往下走D和往右走R。现在要从左上角走到右下角,给定两个操作串,问包含这两个串的走法总共有多少种。
#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 MOD = 1e9 + 7; const int MAXNNODE = 420; const int SIGMA_SIZE = 2; int dp[110][110][220][4]; int M,N; 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) { if (c == 'R') return 0; else return 1; } 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] == 0) { 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 != 0) { fail[u] = 0; q.push(u); last[u] = 0; } //else ch[0][c] = 0; } while (!q.empty()) { int r = q.front();q.pop(); if(val[fail[r]]) 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) { // printf("%d\n",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])); memset(val,0,sizeof(0)); val[0] = 0; } void slove() { memset(dp,0,sizeof(dp)); dp[0][0][0][0] = 1; for (int i = 0 ; i <= M ; i++) for (int j = 0 ; j <= N; j++) for (int s = 0 ; s < sz ; s++) for (int k = 0 ; k < 4 ; k++) { if (dp[i][j][s][k] == 0) continue; int nxt = ch[s][0]; if (i < M) dp[i + 1][j][nxt][k | val[nxt]] = (dp[i + 1][j][nxt][k | val[nxt]] + dp[i][j][s][k]) % MOD; nxt = ch[s][1]; if (j < N) dp[i][j + 1][nxt][k | val[nxt]] = (dp[i][j + 1][nxt][k | val[nxt]] + dp[i][j][s][k]) % MOD; } int ret = 0; for (int i = 0 ; i < sz ; i++) ret = (ret + dp[M][N][i][3]) % MOD; printf("%d\n",ret); } }src; int main() { //freopen("sample.txt","r",stdin); int T; scanf("%d",&T); while (T--) { scanf("%d%d",&M,&N); src.init(); for (int i = 0 ; i < 2; i++) { char str[210]; scanf("%s",str); src.insert(str,1 << i); } src.get_fail(); src.slove(); // for (int i = 0 ; i < src.sz ; i++) // printf("%d %d\n",src.ch[i][0],src.ch[i][1]); } return 0; }
HDU 4511 小明系列故事――女友的考验
#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 double INF = 1e20; const int MAXNNODE = 1010; const int SIGMA_SIZE = 51; double dp[60][MAXNNODE]; int N,M; struct node { double x,y; }input[60]; double dist(int i ,int j) { return sqrt((input[i].x - input[j].x) * (input[i].x - input[j].x) + (input[i].y - input[j].y) * (input[i].y - input[j].y)); } 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(int c) {return c;} void insert(int * s,int v,int n) { int u = 0; 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\n",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])); } double slove() { for (int i = 0 ; i < MAXNNODE ; i++) for (int j = 0 ; j < 60 ; j++) dp[j][i] = INF; dp[1][ch[0][1]] = 0.0; for (int i = 1 ; i <= N; i++) for (int j = 0 ; j < sz ; j++) { if (dp[i][j] == INF) continue; for (int k = i + 1; k <= N; k++) { int nxt = ch[j][k]; if (val[nxt]) continue; dp[k][nxt] = min(dp[k][nxt],dp[i][j] + dist(i,k)); } } double ret = INF; for (int i = 0 ; i < sz ; i++) ret = min(ret,dp[N][i]); return ret; } }src; int main() { // freopen("sample.txt","r",stdin); while (scanf("%d%d",&N,&M) != EOF) { if (N == 0 && M == 0) break; src.init(); for (int i = 1 ; i <= N; i++) scanf("%lf%lf",&input[i].x,&input[i].y); for (int i = 0 ; i < M; i++) { int k; scanf("%d",&k); int tmp[10]; for (int i = 0 ; i < k ; i++) scanf("%d",&tmp[i]); src.insert(tmp,1,k); } src.get_fail(); double ret = src.slove(); if (ret == INF) puts("Can not be reached!"); else printf("%.2lf\n",ret); } return 0; }