传送门

这题暴力对拍都难搞,差评

一般的题解里思路是考虑一般DP:

令\(dp[i][j]\)为枚举到第i位时匹配到第j位的方案数,令\(g[k][j]\)为将匹配到k位的情况补到匹配到j位的方案数

\[dp[i][j] = \sum\limits_{k=0}^{m-1}dp[i-1][k]*g[k][j]
\]

然后这个式子就是矩阵快速幂的形式了

然而我麻烦亿点的做法:

令\(dp[i]\)为长度为i时的合法方案数,辅助数组\(k[i]\)为锁定前\(m\)位为匹配串唯一一次出现时的方案数

考虑转移,则转移为\(dp[i]=dp[i-m]*(10^m-1)\)减去所有跨越\(i-m\)这个边界的不合法方案数

拿以下输入举例子

6 3 1000000

121

这里有几种可能的转移:

121000

×121??

××121?

对于第2行,×有10种可能,??有99种可能(有一种不满足前m位为匹配串唯一一次出现),共990种

对于第3行,××有99种可能(有一种开头是121的已在转移时减掉了,再减就重了),?有10种可能,共990种

所以\(dp[6] = dp[3]*999-990-990 = 996021\)

k数组的转移和dp数组类似,懒得写了不再赘述

时间复杂度\(O((m*2+2)^3logn)\), 也就慢了那么亿点点

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 45
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long int n, m, mod;
int nxt[N], power[N];
bool vis[N];
char s[N]; struct matrix{
int n, m;
int a[N][N];
matrix(){n=m=0; memset(a, 0, sizeof(a));}
matrix(int n_, int m_):n(n_),m(m_) {memset(a, 0, sizeof(a));}
inline void resize(int n_, int m_) {n=n_; m=m_;}
inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<setw(5)<<a[i][j]<<' '; cout<<endl;}}
inline int* operator [] (int i) {return a[i];}
inline matrix operator * (matrix b) {
matrix c(n, b.m);
for (int i=1; i<=n; ++i)
for (int k=1; k<=m; ++k) {
if (!a[i][k]) continue;
for (int j=1; j<=b.m; ++j)
c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod)%mod;
}
return c;
}
}ans, t; matrix qpow(matrix a, int b) {
if (!b) return a;
matrix ans=a; --b;
while (b) {
if (b&1) ans=ans*a;
a=a*a; b>>=1;
}
return ans;
} signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif scanf("%d%d%d%s", &n, &m, &mod, s+1);
nxt[1]=0;
power[0]=1;
for (int i=1; i<=m; ++i) power[i]=power[i-1]*10%mod;
//for (int i=1; i<=m; ++i) cout<<power[i]<<' '; cout<<endl;
int p=(power[m]-1)%mod;
//cout<<p<<endl;
for (int i=2,j=0; i<=m; ++i) {
while (j && s[i]!=s[j+1]) j=nxt[j];
if (s[i]==s[j+1]) ++j;
nxt[i] = j;
}
for (int i=nxt[m]; i; i=nxt[i]) vis[i]=1;
ans.resize(1, m*2+2);
t.resize(m*2+2, m*2+2);
ans[1][1]=-1; ans[1][2]=1;
for (int i=1; i<=m; ++i) ans[1][2+i]=ans[1][1+i]*10%mod;
--ans[1][m+2];
//ans[1][m*2+1]=1; ans[1][m*2+2]=ans[1][m*2+1]*10-(nxt[m]==m-1);
ans[1][m*2+2]=1; t[1][1]=1;
for (int i=1; i<=m; ++i) t[2+i][1+i]=1;
t[3][m+2]=p;
//for (int i=nxt[m]; i; i=nxt[i]) t[m+2+i][m+2]=-1;
for (int i=1; i<m; ++i) t[2*m+3-i][m+2]=-(power[i]-vis[m-i])%mod;
//for (int i=1; i<m; ++i) t[2*m+2-i][m+2]=-1;
for (int i=1; i<m; ++i) t[m+3+i][m+2+i]=1;
//t[m*2+2][m*2+2]=10;
//if (nxt[m]) t[1][m+2+nxt[m]+1]=1;
for (int i=nxt[m]; i; i=nxt[i]) t[m+3+i][m*2+2]=-1;
t[3][m*2+2]=1;
//t[m*2+2][m+2]=-1; #ifdef DEBUG
ans.put(); cout<<endl;
for (int i=1; i<=n-m; ++i) {
ans=ans*t;
ans.put(); cout<<endl;
}
t.put(); cout<<endl;
#else
if (n-m) ans=ans*qpow(t, n-m);
#endif
printf("%d\n", ((ans[1][m+2])%mod+mod)%mod); return 0;
}

题解 [HNOI2008]GT考试的更多相关文章

  1. 【bzoj1009】[HNOI2008]GT考试

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3018  Solved: 1856[Submit][Statu ...

  2. BZOJ_1009_[HNOI2008]_GT考试_(动态规划+kmp+矩阵乘法优化+快速幂)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1009 字符串全部由0~9组成,给出一个串s,求一个长度为n的串,不包含s的种类有多少. 分析 ...

  3. [HNOI2008] GT考试

    [HNOI2008] GT考试 标签 : DP 矩阵乘法 题目链接 题意 n位数中不出现一个子串的方案数. 题解 \(设dp[i][j]\)为前i位匹配到j时的合法方案数.(所谓合法,就是不能有别的匹 ...

  4. BZOJ1009 [HNOI2008]GT考试 矩阵

    去博客园看该题解 题目 [bzoj1009][HNOI2008]GT考试 Description 阿申准备报名参加GT考试,准考证号为N位数X1X2….Xn(0<=Xi<=9),他不希望准 ...

  5. 【BZOJ1009】[HNOI2008]GT考试 next数组+矩阵乘法

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

  6. bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4542  Solved: 2815[Submit][Statu ...

  7. bzoj1009: [HNOI2008]GT考试(kmp+矩阵乘法)

    1009: [HNOI2008]GT考试 题目:传送门 题解: 看这第一眼是不是瞬间想起组合数学??? 没错...这样想你就GG了! 其实这是一道稍有隐藏的矩阵乘法,好题! 首先我们可以简化一下题意: ...

  8. 1009: [HNOI2008]GT考试

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MB Description 阿申准备报名参加GT考试,准考证号为N位数\(X_1X_ ...

  9. BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )

    写了一个早上...就因为把长度为m的也算进去了... dp(i, j)表示准考证号前i个字符匹配了不吉利数字前j个的方案数. kmp预处理, 然后对于j进行枚举, 对数字0~9也枚举算出f(i, j) ...

随机推荐

  1. Android 开发学习进程0.32 dwonloadmanager使用

    downloadmanager时Android系统下载器,使用系统下载器可以避免用stream流读入内存可能导致的内存溢出问题.以下为downloadmanager初始化部分.apkurl为下载网络路 ...

  2. 续PA协商过程

    续PA协商过程 当sw3的接口恢复之后会发生2中情况. ①sw3的G0/0/2口先发BPDU ②sw3的G0/0/3口先发BPDU sw3先发送BPDU sw3和sw1的交互过程: sw3的2口恢复后 ...

  3. Docker以过时,看Containerd怎样一统天下

    Docker作为非常流行的容器技术,之前经常有文章说它被K8S弃用了,取而代之的是另一种容器技术containerd!其实containerd只是从Docker中分离出来的底层容器运行时,使用起来和D ...

  4. java03类与对象相关问题

    1.使用类的静态字段和构造函数,可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向他查询"你已经创建了几个对象" 1 package 第四五周; 2 3 public ...

  5. 论文阅读:hector_slam: A Flexible and Scalable SLAM System with Full 3D Motion Estimation.

    参考:<A Flexible and Scalable SLAM System with Full 3D Motion Estimation.> 该论文是ROS中hector_mappin ...

  6. React事件绑定的方式

    一.是什么 在react应用中,事件名都是用小驼峰格式进行书写,例如onclick要改写成onClick 最简单的事件绑定如下: class ShowAlert extends React.Compo ...

  7. Python+Request库+第三方平台实现验证码识别示例

    1.登录时经常的出现验证码,此次结合Python+Request+第三方验证码识别平台(超级鹰识别平台) 2.首先到超级鹰平台下载对应语言的识别码封装,超级鹰平台:http://www.chaojiy ...

  8. springMVC-8-jackson使用

    springMVC默认的 Json 解决方案是 Jackson, 所以只需要导入 Jackson 的 jar, 即可使用 <!--Jackson--> <dependency> ...

  9. 40.qt quick- 高仿微信实现局域网聊天V4版本(支持gif动图表情包、消息聊天、拖动缩放窗口)

    在上章37.qt quick- 高仿微信实现局域网聊天V3版本(添加登录界面.UDP校验登录.皮肤更换.3D旋转),我们已经实现了: 添加登录界面. UDP校验登录. 皮肤更换. 3D旋转(主界面和登 ...

  10. 开发工具IDE从入门到爱不释手(五)更多实用操作

    更多实用技巧 Tabs分屏和独立 日志链接及浏览器 设置浏览器 本地修改历史 三秒钟不操作,自动保存一个版本 右键--Local History--Show History 查看方法调用情况 按住方法 ...