BZOJ 1009: [HNOI2008]GT考试(DP+KMP失配+矩阵快速幂)
来源:互联网 发布:淘宝外贸原单死人衣服 编辑:程序博客网 时间:2024/05/22 06:53
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4181 Solved: 2552
[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
111
Sample Output
81
好兴奋的做到这么一道题,还发现了其中个别也不知道是否能定义为错误的数据,先说说错误数据的问题,困然我两天,终于忍不住拿别人代码比较,发现矩阵快速幂出了错,相当自信的觉得自己的模板不会错,所以就开始跑数据输出,发现AC的代码会出现负数,AC代码用的数组是int,而longlong的结果跑大数完全不对,所以可能是数据有误,也可能是我理解的不对,不过我感觉出现负数都能过就有点问题了。
然后说说这道想了两天的题,以为模拟可以,但想想这是BZOJ怎么会简单模拟,然后就开始了漫长的演算。感觉数位DP应该是可以的,但是怎么难跟m个字符串联系起来,偷偷看了别人写的,说是KMP的失配函数,然后就去看了看失配数组,果然有收获,想想也是,不就是当前数位的后缀跟m个数的前缀有多少相同的吗,这个地方可以用KMP搞定了,新的问题又来了,DP怎么搞,一看10^9,应该有公式或者矩阵快速幂,然后就在推公式,用DP[i][j]表示第i位数匹配到第j位的种类数。发现DP[i+1][p]+=Dp[i][j],P是匹配到的任意值,也就是说这一项跟前面所有DP[i]的项都有关,通俗点讲就是当前状态的可能种类只与上一状态有关,这正是可以利用矩阵快速幂的原因。next数组储存的就是当这一位数为i时,有多少种可能情况。
好吧,还是把公式打出来吧 dp[i][j]=a0*dp[i-1][0]+a1*dp[i-1][1]+a2*dp[i-1][2]+``````+a(m-1)dp[i-1][m-1]
然后就可以矩阵快速幂了,构造一个m*m的矩阵,系数a就是失配数组求得的种类,跑一遍矩阵快速幂,最后把dp[n][0]到dp[m-1]加起来的值就是结果。
代码中longlong定义的数组,还防止出现负数,如果想A到,longlong变int,然后去掉防止负数就可以了。
代码实现:
#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<cstdio>#define ll long long#define mset(a,x) memset(a,x,sizeof(a))using namespace std;const double PI=acos(-1);const int inf=0x3f3f3f3f;const double esp=1e-6;const int maxn=100000;const int mod=1e9+7;int dir[4][2]={0,1,1,0,0,-1,-1,0};ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll lcm(ll a,ll b){return a/gcd(a,b)*b;}ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}int next[100],n,m,q;char map[100];struct matrix{ int r,c; ll dp[40][40]; matrix(int R=0,int C=0){ memset(dp,0,sizeof(dp)); r=R;c=C; } }a,b;matrix operator*(matrix A,matrix B){ matrix C(A.r,B.c); for(int i=0;i<A.r;i++) {for(int j=0;j<B.c;j++) for(int k=0;k<A.c;k++){ C.dp[i][j]=(C.dp[i][j]+A.dp[i][k]*B.dp[k][j])%q; //防止爆表出现负数 C.dp[i][j]%=q; C.dp[i][j]+=q; C.dp[i][j]%=q; }} return C; }//得到失配函数的next数组,用来构造矩阵 void getfail(){int i=1,j=0; next[1]=0; while(i<=m) { if (j==0||map[i]==map[j]) next[++i]=++j; else j=next[j]; } }//矩阵快速幂 void mat_qpow(){int i,j,k;while(n){if(n&1)a=a*b;n>>=1;b=b*b;}ll ans=0;for(i=0;i<m;i++)ans=(ans+a.dp[0][i])%q;cout<<ans<<endl;}int main(){int i,j,k,l;cin>>n>>m>>q;scanf("%s",map+1);getfail();for(i=0;i<m;i++) //默认匹配到自己的数量为1a.dp[i][i]=1;for(i=1;i<=m;i++) //利用失配数组构造矩阵 {for(j=0;j<=9;j++){int temp=i;while(temp&&map[temp]-'0'!=j)temp=next[temp];b.dp[i-1][temp]++;}}//先进行模除 for(i=0;i<m;i++){for(j=0;j<m;j++)b.dp[i][j]%=q;}a.c=a.r=b.c=b.r=m;mat_qpow();return 0;}/*1000000001110000000011111111111*/
- BZOJ 1009: [HNOI2008]GT考试(DP+KMP失配+矩阵快速幂)
- bzoj 1009: [HNOI2008]GT考试(dp+kmp+矩阵快速幂)
- BZOJ KMP+矩阵快速幂 1009: [HNOI2008]GT考试
- [KMP DP 矩阵快速幂加速] BZOJ 1009 [HNOI2008]GT考试
- BZOJ 1009: [HNOI2008]GT考试【KMP上DP+矩阵快速幂
- BZOJ 1009-GT考试(kmp+矩阵快速幂+DP)
- BZOJ 1009([HNOI2008]GT考试-KMP+矩阵加速Dp)
- 【BZOJ】1009 [HNOI2008]GT考试 KMP+DP+矩阵优化
- BZOJ 1009 GT考试 KMP+DP+矩阵快速幂
- [BZOJ 1009][HNOI2008]GT考试(KMP+线性齐次递推的矩阵加速?+DP)
- [KMP+矩阵快速幂加速]BZOJ 1009——[HNOI2008]GT考试
- BZOJ 1009: [HNOI2008]GT考试 AC自动机+矩阵快速幂
- [bzoj 1009] [HNOI2008]GT考试:DP,单串AC自动机,矩阵快速幂
- BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法
- bzoj 1009: [HNOI2008]GT考试 KMP+矩阵乘法
- 【bzoj1009】[HNOI2008]GT考试 矩阵+kmp+DP
- [BZOJ]1009 [HNOI2008]GT考试(ac自动机+矩阵快速幂优化状态转移)
- 1009: [HNOI2008]GT考试 矩阵乘法优化DP+KMP
- Linux终端部分快捷方式
- C++ 遗传学SFLA混合蛙跳算法
- PopupWindow在7.0上显示的坑
- linux 下 启动mysql服务出错!Starting MySQL.The server quit without updating PID file (XXX.pid)
- Java基础之JMX
- BZOJ 1009: [HNOI2008]GT考试(DP+KMP失配+矩阵快速幂)
- Android 能让你少走弯路的干货整理
- 转发和重定向的对比
- POJ3740-Easy Finding
- Python脚本进行主播招募相关数据统计的案例
- 三星公佈Bixby2.0升級後比蘋果更酷
- 微信小程序获取scope中权限管理
- iOS h5与原生态混编
- Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)【Dalston版】