题意:
给定你n 种字符, 和p 个禁止串, 问你长度为m 的串有多少种 不包含 禁止串?
思路:
AC自动机是显然的。
矩阵快速幂也可以 ,dp 也可以。
但是这是个大数。 极限答案有85位左右。
我用快速幂写了一发,不是爆内存就是因为内存开的过大 小样例都出不来。
只能考虑dp了。
dp 状态很好想:
令dp[i][j] 表示目前走 第i 位长度, 在自动机上j 节点的方案数。
转移就是上一个节点 转下一个节点了。
dp[i][j] += dp[i-1][k]
为了节省空间 搞成滚动数组即可
不过看了看讨论区, 说是 字符串有负数出现 就是 输入 的ASCII码会在128~255之间? 但是我的并没有考虑这种情况, 也A了= =(maybe数据改掉了?)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <string>
#include <istream>
#include <ostream>
using namespace std;
///高精度
const int MAXN = 90;
struct bign
{
int len, s[MAXN];
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[MAXN];
sprintf(s, "%d", num);
*this = s;
return *this;
}
bign operator = (const char *num)
{
for(int i = 0; num[i] == '0'; num++) ; //去前导0
len = strlen(num);
for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0';
return *this;
}
bign operator + (const bign &b) const //+
{
bign c;
c.len = 0;
for(int i = 0, g = 0; g || i < max(len, b.len); i++)
{
int x = g;
if(i < len) x += s[i];
if(i < b.len) x += b.s[i];
c.s[c.len++] = x % 10;
g = x / 10;
}
return c;
}
bign operator += (const bign &b)
{
*this = *this + b;
return *this;
}
void clean()
{
while(len > 1 && !s[len-1]) len--;
}
string str() const
{
string res = "";
for(int i = 0; i < len; i++) res = char(s[i]+'0') + res;
return res;
}
};
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;
}
///
const int maxn = 100 + 3;
char s[100];
int mp[128 ];
int fmp[128];
bign dp[2][maxn];
const int inf = 0x3f3f3f3f;
struct Trie{
int L, root;
int next[maxn][50];
int fail[maxn];
int flag[maxn];
int Hash[maxn];
int fHash[maxn];
int cnt;
int mx;
void init(int mx_){
L = 0;
mx = mx_;
root = newnode();
cnt = 0;
}
int newnode(){
for (int i = 0; i < mx; ++i){
next[L][i] = -1;
}
flag[L] = 0;
return L++;
}
void insert(char* s){
int len = strlen(s);
int nod = root;
for (int i = 0; i < len; ++i){
int id = fmp[s[i] ];
if (next[nod][id] == -1){
next[nod][id] = newnode();
}
nod = next[nod][id];
}
flag[nod] = 1;
}
void bfs(){
fail[root] = root;
queue<int>q;
for (int i = 0; i < mx; ++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();
for (int i = 0; i < mx; ++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]);
}
}
}
}
void deal(){
for (int i = 0; i < L; ++i){
if (flag[i]) continue;
int tmp = i;
while(tmp != root){
if (flag[tmp]){
flag[i] = 1;
break;
}
tmp = fail[tmp];
}
if (!flag[i]){
Hash[cnt++] = i;
fHash[i] = cnt - 1;
}
}
}
void solve(int n){
for (int j = 0; j < maxn; ++j){
dp[0][j] = 0;
}
dp[0][0] = 1;
int foo = 0;
for (int k = 1; k <= n; ++k){
int first = foo;
int second = foo ^ 1;
for (int i = 0; i < maxn; ++i){
dp[second][i] = 0;
}
for (int i = 0; i < cnt; ++i){
for (int j = 0; j < mx; ++j){
int now = Hash[i];
int nx = next[now][j];
if (flag[nx]) continue;
dp[second][nx] += dp[first][now];
}
}
foo ^= 1;
}
bign ans = 0;
for (int i = 0; i < cnt; ++i){
int nod = Hash[i];
ans += dp[foo][nod];
}
string tt = ans.str();
if (tt.length() == 0)cout<<0<<endl;
else cout << ans << endl;
}
}ac;
/**
8881784197001252323389053344726562500000000000000000000000000000000000000000000000000
**/
int main(){
int n, m, p;
scanf("%d %d %d",&n, &m, &p);
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len; ++i){
mp[i] = s[i];
fmp[s[i]] = i;
}
ac.init(len);
for (int i = 0; i < p; ++i){
scanf("%s", s);
ac.insert(s);
}
ac.bfs();
ac.deal();
ac.solve(m);
return 0;
}
Censored! Description The alphabet of Freeland consists of exactly N letters. Each sentence of Freeland language (also known as Freish) consists of exactly M letters without word breaks. So, there exist exactly N^M different Freish sentences. Input The first line of the input file contains three integer numbers: N -- the number of letters in Freish alphabet, M -- the length of all Freish sentences and P -- the number of forbidden words (1 <= N <= 50, 1 <= M <= 50, 0 <= P <= 10). Output Output the only integer number -- the number of different sentences freelanders can safely use. Sample Input 2 3 1abbb Sample Output 5 Source Northeastern Europe 2001, Northern Subregion |
Time Limit: 5000MS | | Memory Limit: 10000K |
Total Submissions: 10370 | | Accepted: 2841 |
[Submit] [Go Back] [Status] [Discuss]