您的位置:首页 > 其它

AC自动机+dp+大数 poj1625

2015-10-23 11:56 211 查看
传送门:点击打开链接

题意:告诉你有哪些字符可以用,然后再告诉你哪些单词不能出现,要你求长度为m的字符串只由给你的字符组成,但是不能出现那些单词的种类数。

思路:..一分析就发现,,貌似爆long long了,,醉了。。总的思路和那个DNA的思路是一样的,用AC自动机完成了矩阵的转移,很逆天的压缩了状态。。除了大数其他和那题基本一样的可以去看看那题..

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

/*MX为总长度*/
const int MX = 2e2 + 5;
const int P = 128;

int G[MX][MX];

struct AC_machine {
int rear, root, ID[MX], s;
int Next[MX][P], Fail[MX], End[MX];

void Init(char *A) {
rear = 0;
s = strlen(A);
for(int i = 0; i < s; i++) {
ID[A[i]] = i;
}
root = New();
}

int New() {
End[rear] = 0;
for(int i = 0; i < s; i++) {
Next[rear][i] = -1;
}
return rear++;
}

void Add(char *A) {
int now = root, n = strlen(A);
for(int i = 0; i < n; i++) {
int id = ID[A[i]];
if(Next[now][id] == -1) {
Next[now][id] = New();
}
now = Next[now][id];
}
End[now] = 1;
}

void Build() {
queue<int>Q;
Fail[root] = root;
for(int i = 0; i < s; i++) {
if(Next[root][i] == -1) {
Next[root][i] = root;
} else {
Fail[Next[root][i]] = root;
Q.push(Next[root][i]);
}
}

while(!Q.empty()) {
int u = Q.front(); Q.pop();

if(End[Fail[u]]) End[u] = 1;
for(int i = 0; i < s; i++) {
if(Next[u][i] == -1) {
Next[u][i] = Next[Fail[u]][i];
} else {
Fail[Next[u][i]] = Next[Fail[u]][i];
Q.push(Next[u][i]);
}
}
}
}

int Query() {
memset(G, 0, sizeof(G));
for(int i = 0; i < rear; i++) {
for(int j = 0; j < s; j++) {
if(End[Next[i][j]] == 0) {
G[i][Next[i][j]]++;
}
}
}
return rear;
}
} AC;

struct BigInteger {
int A[30];
enum {MOD = 10000};
BigInteger() {
memset(A, 0, sizeof(A));
A[0] = 1;
}
void set(int x) {
memset(A, 0, sizeof(A));
A[0] = 1;
A[1] = x;
}
void print() {
printf("%d", A[A[0]]);
for (int i = A[0] - 1; i > 0; i--) {
if (A[i] == 0) {
printf("0000");
continue;
}
for (int k = 10; k * A[i] < MOD; k *= 10) printf("0");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int p) {
return A[p];
}
const int& operator [] (int p) const {
return A[p];
}
BigInteger operator + (const BigInteger& B) {
BigInteger C;
C[0] = max(A[0], B[0]);
for (int i = 1; i <= C[0]; i++)
C[i] += A[i] + B[i], C[i + 1] += C[i] / MOD, C[i] %= MOD;
if (C[C[0] + 1] > 0) C[0]++;
return C;
}
BigInteger operator * (const BigInteger& B) {
BigInteger C;
C[0] = A[0] + B[0];
for (int i = 1; i <= A[0]; i++)
for (int j = 1; j <= B[0]; j++) {
C[i + j - 1] += A[i] * B[j], C[i + j] += C[i + j - 1] / MOD, C[i + j - 1] %= MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
};

char word[MX];
BigInteger dp[2][MX];

int main() {
int n, m, p; //FIN;
while(~scanf("%d%d%d", &n, &m, &p)) {
memset(dp, 0, sizeof(dp));
scanf("%s", word);
AC.Init(word);

for(int i = 1; i <= p; i++) {
scanf("%s", word);
AC.Add(word);
}
AC.Build();
int s = AC.Query();

int cur = 0, nxt = 1;
dp[cur][0].set(1);
for(int i = 1; i <= m; i++) {
for(int j = 0; j < s; j++) {
dp[nxt][j].set(0);
}

for(int j = 0; j < s; j++) {
for(int k = 0; k < s; k++) {
if(G[j][k]) {
BigInteger temp;
temp.set(G[j][k]);
dp[nxt][k] = dp[nxt][k] + dp[cur][j] * temp;
}
}
}
swap(cur, nxt);
}

BigInteger ans;
for(int i = 0; i < s; i++) {
ans = ans + dp[cur][i];
}
ans.print();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: