POJ1625 Censored! AC自动机+dp+高精度

来源:互联网 发布:悬挂焊机控制器编程 编辑:程序博客网 时间:2024/05/17 04:54
/*    题目描述:给出一个有n个字符的字符集,再给出p(0 <= p <= 10)个模式串,问长度为m的字符当中有多少个不含有            任一模式串作为子串。                思路:AC自动机的套路,字典树上的每一个节点表示一种状态,设dp[j][i]表示j节点状态,长度为i的串中满足条件的        有多少个,则有dp[j][i] = Σdp[k][i - 1],其中k节点可以通过一条树边过渡到j节点。本题结果会比较大,要用高精度。            收获:通过此题和POJ2778,巩固了这样一个事实:AC自动机的字典树中的每一个节点代表了一个状态,并且通过        树边就可以知道这个状态可以转移到其它的什么状态*/#pragma warning(disable:4786)#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>#include<queue>#include<map>#include<set>#include<vector>#include<cmath>#include<string>#include<sstream>#include<bitset>#define LL long long#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)#define mem(a,x) memset(a,x,sizeof(a))#define lson l,m,x<<1#define rson m+1,r,x<<1|1using namespace std;const int INF = 0x3f3f3f3f;const double PI = acos(-1.0);const double eps = 1e-6;const int MAXNODE = 50 * 50 + 5;const int MAXS = 12;const int NUM = 105;const int MAX_SIGMA_SIZE = 55;int SIGMA_SIZE;int maxn;int vis[500];/** 完全大数模板* 输出cin>>a* 输出a.print();* 注意这个输入不能自动去掉前导0的,可以先读入到char数组,去掉前导0,再用构造函数。*/#define MAXN 9999#define MAXSIZE 50#define DLEN 4class BigNum{public:int a[MAXSIZE];  //可以控制大数的位数int len;public:BigNum(){ len = 1; memset(a, 0, sizeof(a)); }  //构造函数BigNum(const int);     //将一个int类型的变量转化成大数BigNum(const char*);   //将一个字符串类型的变量转化为大数BigNum(const BigNum &); //拷贝构造函数BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算friend istream& operator>>(istream&, BigNum&); //重载输入运算符friend ostream& operator<<(ostream&, BigNum&); //重载输出运算符BigNum operator+(const BigNum &)const;  //重载加法运算符,两个大数之间的相加运算BigNum operator-(const BigNum &)const;  //重载减法运算符,两个大数之间的相减运算BigNum operator*(const BigNum &)const;  //重载乘法运算符,两个大数之间的相乘运算BigNum operator/(const int &)const;     //重载除法运算符,大数对一个整数进行相除运算BigNum operator^(const int &)const;     //大数的n次方运算int operator%(const int &)const;        //大数对一个int类型的变量进行取模运算bool operator>(const BigNum &T)const;   //大数和另一个大数的大小比较bool operator>(const int &t)const;      //大数和一个int类型的变量的大小比较void print();        //输出大数};BigNum::BigNum(const int b)   //将一个int类型的变量转化为大数{int c, d = b;len = 0;memset(a, 0, sizeof(a));while (d>MAXN){c = d - (d / (MAXN + 1))*(MAXN + 1);d = d / (MAXN + 1);a[len++] = c;}a[len++] = d;}BigNum::BigNum(const char *s)  //将一个字符串类型的变量转化为大数{int t, k, index, L, i;memset(a, 0, sizeof(a));L = strlen(s);len = L / DLEN;if (L%DLEN)len++;index = 0;for (i = L - 1; i >= 0; i -= DLEN){t = 0;k = i - DLEN + 1;if (k<0)k = 0;for (int j = k; j <= i; j++)t = t * 10 + s[j] - '0';a[index++] = t;}}BigNum::BigNum(const BigNum &T) :len(T.len)  //拷贝构造函数{int i;memset(a, 0, sizeof(a));for (i = 0; i<len; i++)a[i] = T.a[i];}BigNum & BigNum::operator=(const BigNum &n)  //重载赋值运算符,大数之间赋值运算{int i;len = n.len;memset(a, 0, sizeof(a));for (i = 0; i<len; i++)a[i] = n.a[i];return *this;}istream& operator>>(istream &in, BigNum &b){char ch[MAXSIZE * 4];int i = -1;in >> ch;int L = strlen(ch);int count = 0, sum = 0;for (i = L - 1; i >= 0;){sum = 0;int t = 1;for (int j = 0; j<4 && i >= 0; j++, i--, t *= 10){sum += (ch[i] - '0')*t;}b.a[count] = sum;count++;}b.len = count++;return in;}ostream& operator<<(ostream& out, BigNum& b)  //重载输出运算符{int i;cout << b.a[b.len - 1];for (i = b.len - 2; i >= 0; i--){printf("%04d", b.a[i]);}return out;}BigNum BigNum::operator+(const BigNum &T)const   //两个大数之间的相加运算{BigNum t(*this);int i, big;big = T.len>len ? T.len : len;for (i = 0; i<big; i++){t.a[i] += T.a[i];if (t.a[i]>MAXN){t.a[i + 1]++;t.a[i] -= MAXN + 1;}}if (t.a[big] != 0)t.len = big + 1;else t.len = big;return t;}BigNum BigNum::operator*(const BigNum &T)const  //两个大数之间的相乘{BigNum ret;int i, j, up;int temp, temp1;for (i = 0; i<len; i++){up = 0;for (j = 0; j<T.len; j++){temp = a[i] * T.a[j] + ret.a[i + j] + up;if (temp>MAXN){temp1 = temp - temp / (MAXN + 1)*(MAXN + 1);up = temp / (MAXN + 1);ret.a[i + j] = temp1;}else{up = 0;ret.a[i + j] = temp;}}if (up != 0)ret.a[i + j] = up;}ret.len = i + j;while (ret.a[ret.len - 1] == 0 && ret.len>1)ret.len--;return ret;}void BigNum::print()   //输出大数{int i;printf("%d", a[len - 1]);for (i = len - 2; i >= 0; i--)printf("%04d", a[i]);printf("\n");}bool ONE(BigNum a){if (a.len == 1 && a.a[0] == 1)return true;else return false;}BigNum A, B, X, Y;struct AhoCorasickAutomata{int ch[MAXNODE][MAX_SIGMA_SIZE];int f[MAXNODE];int last[MAXNODE];int val[MAXNODE];int ok[MAXNODE];int sz;void init(){mem(ch[0], 0);sz = 1;}int idx(char c){return vis[c];}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]){mem(ch[sz], 0);val[sz] = 0;ch[u][c] = sz++;}u = ch[u][c];}++val[u];}void print(int j){if (j){printf("%d: %d\n", j, val[j]);print(last[j]);}}void getFail(){queue<int>Q;f[0] = 0;for (int i = 0; i < SIGMA_SIZE; i++){int u = ch[0][i];if (u){f[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){ch[r][c] = ch[f[r]][c];         continue;}Q.push(u);int v = f[r];f[u] = ch[v][c];last[u] = val[f[u]] ? f[u] : last[f[u]];}}}}ac;char p[55];BigNum dp[502][52];int main(){int m, fw;while (scanf("%d %d %d", &SIGMA_SIZE, &m, &fw) != EOF){ac.init();mem(vis, 0);getchar();gets(p);for (int i = 0; i < SIGMA_SIZE; i++){vis[p[i]] = i;}for (int i = 1; i <= fw; i++){gets(p);ac.insert(p);}ac.getFail();for (int i = 0; i <= m; i++){for (int j = 0; j < ac.sz; j++){dp[j][i] = BigNum(0);}}dp[0][0] = BigNum(1);for (int i = 0; i < m; i++){for (int j = 0; j < ac.sz; j++){if (ac.val[j] || ac.last[j])continue;for (int c = 0; c < SIGMA_SIZE; c++){int u = ac.ch[j][c];if (ac.val[u] || ac.last[u])continue;dp[u][i + 1] = dp[u][i + 1] + dp[j][i];}}}BigNum ans = BigNum(0);for (int i = 0; i < ac.sz; i++){if (!ac.val[i] && !ac.last[i])ans = ans + dp[i][m];}cout << ans << endl;}return 0;}

0 0