题目大意:用k种字符构建两个长度为n的字符串(每种字符有无限多个),要求对应位置字符相同的连续子串最长长度为m,问方法数。

其中k,n,m是输入,n(1<=n<=1000000000), m(1<=m<=10), k(1<=k<=26).

对题目解释更详细点儿,如下两串

123456

223466

这个的“对应位置字符相同的连续子串最长长度”是3,是字符串“234”。

解题思路,这题一看就是DP或者组合数学,但是不会组合数学,只能DP了
dp[i][j]表示前i个字符,最后j个位置相同的方法数

第三维01表示该状态是否包含了至少一个长度为m的“对应位置相同子串”

dp[i][j][0]=dp[i-1][j-1][0]*k                                                          (0<j<m)
dp[i][0][0]=sum(dp[i-1][0到m-1][0])*k*(k-1)
dp[i][j][1]=dp[i-1][j-1][1]*k                                                          (0<j<=m)
dp[i][0][1]=(sum(dp[i-1][0到m][1])+dp[i-1][m-1][0])*k*(k-1)
 
由于第一维范围过大,且只和前一个状态有关,很明显想到矩阵乘法优化递推。完整代码如下:
 #include <iostream>
#include <cstdio>
#include <cstring> using namespace std;
typedef long long ll;
const int N = ;
const ll MOD=;
struct Mat {
ll mat[N][N];
Mat()
{
memset(mat,,sizeof(mat));
}
void clear(){
memset(mat,,sizeof(mat));
}
}; ll num[N];
int n, m,K;
Mat a; void init() {
//初始化状态转移矩阵
a.clear();
for(int j=;j<m;j++)a.mat[][j]=K*(K-);
for(int i=;i<m;i++)a.mat[i][i-]=K;
for(int j=m;j<=*m;j++)a.mat[m][j]=K*(K-);
for(int i=m+;i<=*m;i++)a.mat[i][i-]=K;
a.mat[*m][m-]=K;
} Mat operator * (Mat a, Mat b) {
Mat c;
for(int i=;i<=*m;i++){
for(int j=;j<=*m;j++){
for(int k=;k<=*m;k++){
c.mat[i][j]+=b.mat[i][k]*a.mat[k][j];
c.mat[i][j]%=MOD;
}
}
}
return c;
} Mat operator ^ (Mat a, int k) {
//初状态
Mat c;
c.mat[][]=;
//快速幂
for(; k; k >>= ) {
if(k&) c = c*a;
a = a*a;
}
return c;
} int main() {
//freopen("data.in", "r", stdin);
int T;
scanf("%d",&T);
while(~scanf("%d%d%d",&n,&m,&K)) {
//初始化状态转移矩阵
init();
//矩阵快速幂,初始左矩阵不是单位矩阵,是初状态
a = a^n;
//得到最终矩阵后求答案
ll ans=;
for(int i = m; i <= *m; ++i) {
ans+=a.mat[i][];
ans%=MOD;
}
printf("%lld\n", ans);
}
return ;
}

HDU 5863

然后写这个主要是想记录下矩阵乘法的板子

#include <iostream>
#include <cstdio>
#include <cstring> using namespace std;
typedef long long ll;
const int N = ;
const long long MOD=;
struct Mat {
ll mat[N][N];
Mat()
{
memset(mat,,sizeof(mat));
}
void clear(){
memset(mat,,sizeof(mat));
}
}; ll num[N];
int n, m,K;
Mat a; void init() {
//初始化状态转移矩阵
a.clear();
for(int j=;j<m;j++)a.mat[][j]=K*(K-);
for(int i=;i<m;i++)a.mat[i][i-]=K;
for(int j=m;j<=*m;j++)a.mat[m][j]=K*(K-);
for(int i=m+;i<=*m;i++)a.mat[i][i-]=K;
a.mat[*m][m-]=K;
} Mat operator * (Mat a, Mat b) {
Mat c;
for(int i=;i<=*m;i++){
for(int j=;j<=*m;j++){
for(int k=;k<=*m;k++){
c.mat[i][j]+=b.mat[i][k]*a.mat[k][j];
c.mat[i][j]%=MOD;
}
}
}
return c;
} Mat operator ^ (Mat a, int k) {
//初状态
Mat c;
c.mat[][]=;
//快速幂
for(;k;k>>=){
if(k&)c=c*a;
a=a*a;
}
return c;
} int main() {
//freopen("data.in", "r", stdin);
//初始化状态转移矩阵
init();
//矩阵快速幂,初始左矩阵不是单位矩阵,是初状态
a = a^n;
return ;
}
 
 

最新文章

  1. Unslider.js Tiny Sample
  2. css3 filter属性在项目中的应用
  3. Sunny-Code Beta版总结会议
  4. C# exe dll防止反编译-- dotNET_Reactor
  5. PHP 页面跳转方法
  6. sqlserver执行sql文件命令(sqlcmd)
  7. 第35讲:List的map、flatMap、foreach、filter操作代码实战
  8. C#网络通信
  9. nginx错误汇总
  10. 软件测试 homework2
  11. L9-3.安装PHP软件包
  12. Codeforces Round#1
  13. 数组名取地址所算数运算应注意的&amp;quot;trap&amp;quot;
  14. vue组件最佳实践
  15. 原生JS实现弹出窗口的拖拽
  16. windows 2008 R2操作系统上使用iis服务运行php和mysql数据库的网站遇到的验证码不显示问题?
  17. List转换成JSON对象报错(四)
  18. FileInputStream文件字节输入流程序
  19. Java笔记(十)堆与优先级队列
  20. NYOJ 737:石子合并(一)(区间dp)

热门文章

  1. MATLAB 2018a 下载安装
  2. maven nexus memory optimization
  3. winfrom窗体属性
  4. [转]解决C# WinForm 中 VSHOST.EXE 程序不关闭的问题
  5. Struts2的学习链接
  6. 错误:the apk for your currently selected variant(app-release-unsigned.apk)is not signed.Please specity a signing configuration for this variant(release)
  7. Nginx下修改php.ini后重新加载配置文件命令
  8. 00--C++牛人的博客
  9. Linux crontab 在每月最后一天执行
  10. json与object