博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 5863 cjj's string game ( 16年多校10 G 题、矩阵快速幂优化线性递推DP )
阅读量:5135 次
发布时间:2019-06-13

本文共 3685 字,大约阅读时间需要 12 分钟。

题意 : 有种不同的字符,每种字符有无限个,要求用这k种字符构造两个长度为n的字符串a和b,使得a串和b串的最长公共部分长度恰为m,问方案数 

 

分析 :

直觉是DP

不过当时看到 n 很大、但是 m 很小的时候

发现此题DP并不合适、于是想可能是某种组合数学的问题可以直接公式算

看到题解的我、恍然大悟、对于这种数据、可以考虑一下矩阵快速幂优化的DP

首先要想到线性递推的 DP 式子

最直观的想法就是 dp[i][j] = 到第 i 个位置为止、前面最长匹配长度为 j 的方案数

但是如果仔细想想、这样子的定义状态并不好转移、遂换一种思路

定义 dp[i][j] = 到第 i 个位置为止、以第 i 个字符为结尾的匹配串的长度为 j 的方案数

有转移

dp[i][0] = (dp[i-1][0] + dp[i-1][1] + .... + dp[i-1][m] ) * k * (k-1)   (k * (k-1) 的意义是a、b串第 i 个字符不一样的方案数)

dp[i][j] = dp[i-1][j-1] * k ( j ≤ i )

然后尝试去构造矩阵、此处引用

但是注意一下这里的 DP 意义、答案最后并不是 dp[n][m]

dp[n][0] + dp[n][1] + ... + dp[n][m] 可以看成到第 n 个位置为止匹配长度 ≤ m 的方案数

那么如果可以得到匹配长度 ≤ m-1 的方案数两者相减就可以得到匹配长度恰为 m 的方案数了

所以做两次矩阵快速幂即可

 

#include
#define LL long long#define ULL unsigned long long#define scl(i) scanf("%lld", &i)#define scll(i, j) scanf("%lld %lld", &i, &j)#define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)#define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)#define scs(i) scanf("%s", i)#define sci(i) scanf("%d", &i)#define scd(i) scanf("%lf", &i)#define scIl(i) scanf("%I64d", &i)#define scii(i, j) scanf("%d %d", &i, &j)#define scdd(i, j) scanf("%lf %lf", &i, &j)#define scIll(i, j) scanf("%I64d %I64d", &i, &j)#define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)#define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)#define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)#define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)#define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)#define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)#define lson l, m, rt<<1#define rson m+1, r, rt<<1|1#define lowbit(i) (i & (-i))#define mem(i, j) memset(i, j, sizeof(i))#define fir first#define sec second#define VI vector
#define ins(i) insert(i)#define pb(i) push_back(i)#define pii pair
#define VL vector
#define mk(i, j) make_pair(i, j)#define all(i) i.begin(), i.end()#define pll pair
#define _TIME 0#define _INPUT 0#define _OUTPUT 0clock_t START, END;void __stTIME();void __enTIME();void __IOPUT();using namespace std;const int maxn = 1e5 + 10;const LL mod = 1e9 + 7;struct MAT{ LL val[12][12]; int sz; MAT(){}; MAT(int _sz){ sz = _sz; memset(val, 0, sizeof(val)); } friend MAT operator * (const MAT & A, const MAT & B){ MAT C(A.sz); for(int k = 1; k <= C.sz; k++) for(int i = 1; i <= C.sz; i++){ if(A.val[i][k] == 0) continue; for(int j = 1; j <= C.sz; j++){ C.val[i][j] = C.val[i][j] + A.val[i][k] * B.val[k][j] % mod; if(C.val[i][j] >= mod) C.val[i][j] -= mod; } } return C; }};MAT pow_mod(MAT a, LL b){ MAT ret(a.sz); for(int i=1; i<=ret.sz; i++) ret.val[i][i] = 1; while(b){ if(b & 1) ret = ret * a; a = a * a; b >>= 1; }return ret;}LL Cal(int n, int m, int k){ MAT A(m+1); for(int i=1; i<=A.sz; i++) A.val[1][i] = 1LL * k * (k - 1); for(int i=2; i<=A.sz; i++) A.val[i][i-1] = k * 1LL; A = pow_mod(A, n); LL ret = 0; for(int i=1; i<=A.sz; i++) ret = (ret + A.val[i][1]) % mod; return ret;}int main(void){__stTIME();__IOPUT(); int nCase; sci(nCase); while(nCase--){ int n, m, k; sciii(n, m, k); printf("%lld\n", (Cal(n, m, k) - Cal(n, m-1, k) + mod) % mod); }__enTIME();return 0;}void __stTIME(){ #if _TIME START = clock(); #endif}void __enTIME(){ #if _TIME END = clock(); cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<
View Code

 

转载于:https://www.cnblogs.com/LiHior/p/9797051.html

你可能感兴趣的文章
【题解】[P4178 Tree]
查看>>
QML学习笔记之一
查看>>
WPF中实现多选ComboBox控件
查看>>
ionic2+ 基础
查看>>
MyBaits动态sql语句
查看>>
用户空间与内核空间,进程上下文与中断上下文[总结]
查看>>
JAVA开发环境搭建
查看>>
Visual Studio基于CMake配置opencv1.0.0、opencv2.2
查看>>
SDN第四次作业
查看>>
django迁移数据库错误
查看>>
Data truncation: Out of range value for column 'Quality' at row 1
查看>>
字符串处理
查看>>
HtmlUnitDriver 网页内容动态抓取
查看>>
ad logon hour
查看>>
罗马数字与阿拉伯数字转换
查看>>
Eclipse 反编译之 JadClipse
查看>>
距离公式汇总以及Python实现
查看>>
Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
查看>>
第23月第24天 git命令 .git-credentials git rm --cached git stash clear
查看>>
java SE :标准输入/输出
查看>>