HDU 5863 cjj's string game(dp+矩阵快速幂)
2016-09-03 10:20
309 查看
Description
有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数
Input
第一行一整数T表示用例组数,每组用例输入三个整数n,m,k
(1<=T<=100,1<=n<=10^9,1<=m<=10,1<=k<=26)
Output
对于每组用例,输出方案数,结果模1e9+7
Sample Input
2
3 2 3
3 3 3
Sample Output
108
27
Solution
考虑最长匹配的位置,可能以最后一个字符结尾,也可能以前面某个字符结尾,之后的讨论中我们不妨将以最后一个字符结尾的m-匹配称为最后出现的最长匹配,不以最后一个字符结尾的m-匹配称为前面出现的最长匹配,那么我们以dp[i][j]表示以i结尾,匹配了j长度的方案数,那么我们根据第i个位置的放法有以下转移
dp[i][0]=(dp[i-1][0]+…+dp[i-1][m]) * k * (k-1)
dp[i][j]=dp[i-1][j-1] * k,j=1,2,…,m
用矩阵快速幂加速这个dp可以得到dp
[0]~dp
[m],即
令sum=dp
[0]+dp
[1]…+dp
[m],那么sum的意义可以解释为前面出现的最长匹配<=m的方案,最后出现的最长匹配<=m的方案,而我们要求的是前面出现的最长匹配<=m,最后出现的最长匹配<=m,且两个等号至少一个成立的方案,那么去掉不合法的即可,不合法方案即为前面出现的最长匹配<=m-1的方案,最后出现的最长匹配<=m-1的方案,这就是将原来dp转移转移过程中的m变成m-1后的子问题,故做两遍矩阵快速幂,将sum值做差即为答案
Code
有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数
Input
第一行一整数T表示用例组数,每组用例输入三个整数n,m,k
(1<=T<=100,1<=n<=10^9,1<=m<=10,1<=k<=26)
Output
对于每组用例,输出方案数,结果模1e9+7
Sample Input
2
3 2 3
3 3 3
Sample Output
108
27
Solution
考虑最长匹配的位置,可能以最后一个字符结尾,也可能以前面某个字符结尾,之后的讨论中我们不妨将以最后一个字符结尾的m-匹配称为最后出现的最长匹配,不以最后一个字符结尾的m-匹配称为前面出现的最长匹配,那么我们以dp[i][j]表示以i结尾,匹配了j长度的方案数,那么我们根据第i个位置的放法有以下转移
dp[i][0]=(dp[i-1][0]+…+dp[i-1][m]) * k * (k-1)
dp[i][j]=dp[i-1][j-1] * k,j=1,2,…,m
用矩阵快速幂加速这个dp可以得到dp
[0]~dp
[m],即
令sum=dp
[0]+dp
[1]…+dp
[m],那么sum的意义可以解释为前面出现的最长匹配<=m的方案,最后出现的最长匹配<=m的方案,而我们要求的是前面出现的最长匹配<=m,最后出现的最长匹配<=m,且两个等号至少一个成立的方案,那么去掉不合法的即可,不合法方案即为前面出现的最长匹配<=m-1的方案,最后出现的最长匹配<=m-1的方案,这就是将原来dp转移转移过程中的m变成m-1后的子问题,故做两遍矩阵快速幂,将sum值做差即为答案
Code
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; #define mod 1000000007ll #define maxn 11 struct Mat { ll mat[maxn][maxn];//矩阵 int row,col;//矩阵行列数 }; ll mod_Pow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1)ans=ans*a%p; a=a*a%p; b>>=1; } return ans; } Mat mod_mul(Mat a,Mat b,int p)//矩阵乘法 { Mat ans; ans.row=a.row; ans.col=b.col; memset(ans.mat,0,sizeof(ans.mat)); for(int i=0;i<ans.row;i++) for(int k=0;k<a.col;k++) if(a.mat[i][k]) for(int j=0;j<ans.col;j++) { ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%p; ans.mat[i][j]%=p; } return ans; } Mat mod_pow(Mat a,int k,int p)//矩阵快速幂 { Mat ans; ans.row=a.row; ans.col=a.col; for(int i=0;i<a.row;i++) for(int j=0;j<a.col;j++) ans.mat[i][j]=(i==j); while(k) { if(k&1)ans=mod_mul(ans,a,p); a=mod_mul(a,a,p); k>>=1; } return ans; } ll n; int T,m,k; ll Solve(int m) { Mat A; A.col=A.row=m+1; memset(A.mat,0,sizeof(A.mat)); for(int i=0;i<=m;i++)A.mat[0][i]=k*(k-1); for(int i=1;i<=m;i++)A.mat[i][i-1]=k; A=mod_pow(A,n,mod); ll ans=0; for(int i=0;i<=m;i++)ans=(ans+A.mat[i][0])%mod; return ans; } int main() { scanf("%d",&T); while(T--) { scanf("%I64d%d%d",&n,&m,&k); ll ans=Solve(m)-Solve(m-1); printf("%I64d\n",(ans%mod+mod)%mod); } return 0; }
相关文章推荐
- Hdu-5863 cjj's string game(矩阵快速幂)
- HDU 5863 cjj's string game(矩阵快速幂) ★
- HDU 5863 cjj's string game(矩阵快速幂)
- 矩阵快速幂,动态规划(cjj's string game,HDU 5863)
- HDU - 5863 cjj's string game 矩阵快速幂
- HDU 5863 cjj's string game(矩阵dp)
- HDU 5863 cjj's string game(矩阵快速幂)
- HDU 5863 cjj's string game(矩阵优化DP)
- HDU - 5863 - cjj's string game (递推)
- HDU 5863 cjj's string game 快速幂 dp
- HDU 5860 cjj's string game
- HDU5863 cjj's string game (dp+矩阵快速幂)
- HDU 5863 cjj's string game
- HDU5863-cjj's string game
- hdu5863 cjj's string game
- hdu 3915 Game
- 2011 上海网选 HDU 4023 Game (博弈+人工智能)
- hdu 3336 Count the string
- 杭电 hdu 3336 Count the string
- hdu 4023 Game