# 字符串构造的dp 【bzoj1009 &bzoj1030】

## 1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4305  Solved: 2637
[Submit][Status][Discuss]

## Description

阿申准备报名参加GT考试，准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。

0

## Input

第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

## Output

阿申想知道不出现不吉利数字的号码有多少种，输出模K取余的结果.

4 3 100
111

## Sample Output

81

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 100005,maxm = 25,INF = 1000000000;

int n,m,P;
char s[maxn];
int nxt[maxn];

struct Matrix{
int s[maxm][maxm],n,m;
Matrix() {memset(s,0,sizeof(s)); n = m = 0;}
}A;

inline Matrix operator * (const Matrix& a,const Matrix& b){
Matrix c;
if (a.m != b.n) return c;
c.n = a.n; c.m = b.m;
for (int i = 0 ; i < c.n; i++)
for (int j = 0; j < c.m; j++)
for (int k = 0; k < a.m; k++)
c.s[i][j] = (c.s[i][j] + a.s[i][k] * b.s[k][j]) % P;
return c;
}

inline Matrix qpow(Matrix a,LL b){
Matrix ans; ans.n = ans.m = a.n;
for (int i = 0; i < ans.n; i++) ans.s[i][i] = 1;
for (; b; b >>= 1,a = a * a)
if (b & 1) ans = ans * a;
return ans;
}

void getf(){
for (int i = 1 ; i < m; i++){
int j = nxt[i];
while (j && s[j] != s[i]) j = nxt[j];
nxt[i + 1] = s[j] == s[i] ? j + 1 : 0;
}
}

void init(){
cin>>n>>m>>P>>s;
getf();
for (int i = 0; i < m; i++){
for (char j = '0'; j <= '9'; j++){
int k = i;
while (k && s[k] != j) k = nxt[k];
if (s[k] == j) k++;
if (k != m) A.s[i][k]++;
}
}
A.n = A.m = m;
}

void solve(){
Matrix F = qpow(A,n),Ans;
Ans.n = 1; Ans.m = m;
Ans.s[0][0] = 1;
Ans = Ans * F;
int ans = 0;
for (int i = 0; i < m; i++)
ans = (ans + Ans.s[0][i]) % P;
cout<<ans<<endl;
}

int main()
{
init();
//cout<<"h"<<endl;
solve();
return 0;
}


## 1030: [JSOI2007]文本生成器

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 5248  Solved: 2166
[Submit][Status][Discuss]

## Description

JSOI交给队员ZYX一个任务，编制一个称之为“文本生成器”的电脑软件：该软件的使用者是一些低幼人群，

## Input

输入文件的第一行包含两个正整数，分别是使用者了解的单词总数N (<= 60)，GW文本生成器 v6生成的文本固

## Output

一个整数，表示可能的文章总数。只需要知道结果模10007的值。

2 2
A
B

## Sample Output

100

f[i][j]表示到i位置后缀为trie树中的j节点的方案数

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 10005,maxm = 105,INF = 1000000000,P = 10007;

int N,M,ch[maxn][26],tag[maxn],fail[maxn],siz = 0,f[maxm][maxn];
char A[maxm];
void insert(){
int n = strlen(A),u = 0,id;
for (int i = 0; i < n; i++){
id = A[i] - 'A';
u = ch[u][id] ? ch[u][id] : ch[u][id] = ++siz;
}
tag[u] = true;
}
void getf(){
queue<int> q;
for (int i = 0; i < 26; i++) if (ch[0][i]) q.push(ch[0][i]);
int u,v;
while (!q.empty()){
u = q.front();
q.pop();
for (int i = 0; i < 26; i++){
v = ch[u][i];
if (!v) ch[u][i] = ch[fail[u]][i];
else fail[v] = ch[fail[u]][i],q.push(v);
}
if (tag[fail[u]]) tag[u] = true;
}
}
int main()
{
cin >> N >> M;
REP(i,N) scanf("%s",A),insert();
getf(); f[0][0] = 1;
for (int i = 0; i < M; i++){
for (int j = 0; j <= siz; j++){
if (tag[j] || !f[i][j]) continue;
for (int k = 0; k < 26; k++){
int v = ch[j][k];
f[i + 1][v] = (f[i + 1][v] + f[i][j]) % P;
}
}
}
int ans = 1;
REP(i,M) ans = ans * 26 % P;
for (int i = 0; i <= siz; i++) if (!tag[i]) ans = (ans - f[M][i] + P) % P;
cout<<ans<<endl;
return 0;
}


posted @ 2017-11-26 10:07  Mychael  阅读(116)  评论(0编辑  收藏