您的位置:首页 > 其它

BZOJ1009: [HNOI2008]GT考试

2018-01-20 15:07 357 查看

1009: [HNOI2008]GT考试

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 4474 Solved: 2763
[Submit][Status][Discuss]

Description

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

他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为

0

Input

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

Output

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

Sample Input

4 3 100

111

Sample Output

81

HINT

Source

【题解】

不妨设dp[i][j]表示前i个字符,后缀有j个匹配上了,其余的没有匹配上

他们说做多了AC自动机上DP就能想出这个状态。。

可我还没写过AC自动机的题

预处理a[i][j]表示长度为i的前缀加上一个字符到达长度为j的前缀的方案数

转移为dp[i][j] = Σdp[i-1][k] * a[k][j]

很明显的矩阵乘法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
inline void swap(int &a, int &b)
{
long long tmp = a;a = b;b = tmp;
}
inline void read(int &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}

const int INF = 0x3f3f3f3f;
const int MAXM = 30;

int a[MAXM][MAXM], p[MAXM][MAXM], nxt[MAXM], k, n, m;
char s[MAXM];

void kmp()
{
nxt[0] = -1;
for(register int i = 1, j = -1;i < m;++ i)
{
while(j >= 0 && s[i] != s[j + 1]) j = nxt[j];
if(s[i] == s[j + 1]) ++ j;
nxt[i] = j;
}
for(register int i = 0;i < m;++ i)
for(register int j = '0';j <= '9';++ j)
{
int tmp = i - 1;
while(tmp >= 0 && s[tmp + 1] != j)
tmp = nxt[tmp];
if(s[tmp + 1] == j) ++ a[i][tmp + 2];
else ++ a[i][0];
}
}

int tmp[MAXM][MAXM], base[MAXM][MAXM];

void pow(int b)
{
for(register int i = 0;i < m;++ i)
for(register int j = 0;j < m;++ j)
base[i][j] = a[i][j];
for(;b;b >>= 1)
{
if(b & 1)
{
memset(tmp, 0, sizeof(tmp));
for(register int i = 0;i < m;++ i)
for(register int j = 0;j < m;++ j)
for(register int q = 0;q < m;++ q)
{
tmp[i][j] += a[i][q] * base[q][j] % k;
if(tmp[i][j] >= k) tmp[i][j] -= k;
}
for(register int i = 0;i < m;++ i)
for(register int j = 0;j < m;++ j)
a[i][j] = tmp[i][j];
}
memset(tmp, 0, sizeof(tmp));
for(register int i = 0;i < m;++ i)
for(register int j = 0;j < m;++ j)
for(register int q = 0;q < m;++ q)
{
tmp[i][j] += base[i][q] * base[q][j] % k;
if(tmp[i][j] >= k) tmp[i][j] -= k;
}
for(register int i = 0;i < m;++ i)
for(register int j = 0;j < m;++ j)
base[i][j] = tmp[i][j];
}
}

int main()
{
read(n), read(m), read(k);scanf("%s", s);
kmp();
pow(n - 1);
int sum = 0;
for(register int i = 0;i < m;++ i)
{
sum += a[0][i];
if(sum >= k) sum -= k;
}
printf("%d", sum);
return 0;
}


BZOJ1009
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: