/*
题目描述:给出一个有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|1
using 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 4
class 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;
}
POJ1625 Censored! AC自动机+dp+高精度
最新推荐文章于 2022-10-01 15:21:43 发布