题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=5564
-----------------------------------------------------------------------------------------
刚读完题目感觉像是数位DP,然而仔细看了数据范围后感觉很不可做。
与数位DP题目对比可以发现 此题数据范围要大一些,却没有对每一位进行限制
于是便可以愉快地进行矩阵乘法优化DP啦
如果矩阵构造(将递推式转换为矩阵形式)还不熟练的话 可以参考
挑战程序设计竞赛(第2版) 3.4.2节
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mod = 1e9 + 7, L = 70 + 1; int t, l, r, m; long long raw[L][L], tmp[L][L], a[L][L], b[L][L], f[L]; long long ans1, ans2; void mul(long long A[L][L], long long B[L][L]) { memset(tmp, 0, sizeof tmp); for(int i = 0; i < L; ++i) for(int j = 0; j < L; ++j) { for(int k = 0; k < L; ++k) tmp[i][j] += A[i][k] * B[k][j] % mod; tmp[i][j] %= mod; } for(int i = 0; i < L; ++i) for(int j = 0; j < L; ++j) A[i][j] = tmp[i][j]; } long long solve(int lim) { if(!lim) return 0; if(lim == 1) return 1; lim -= 2; for(int i = 0; i < L; ++i) for(int j = 0; j < L; ++j) a[i][j] = b[i][j] = raw[i][j]; while(lim) { if(lim & 1) mul(a, b); mul(b, b); lim >>= 1; } long long tans = 0; for(int i = 0; i < L; ++i) tans += a[70][i] * f[i] % mod; return tans % mod; } int main() { for(int i = 1; i <= 9; ++i) f[i * 7 + i % 7] = 1; f[70] = 1; scanf("%d", &t); while(t--) { scanf("%d%d%d", &l, &r, &m); memset(raw, 0, sizeof raw); for(int i = 0; i <= 9; ++i) for(int j = 0; j <= 9; ++j) if(i + j != m) { for(int k = 0; k < 7; ++k) { raw[i * 7 + (k * 10 + i) % 7][j * 7 + k] = 1; if((k * 10 + i) % 7 == 0) ++raw[70][j * 7 + k]; } } raw[70][70] = 1; ans1 = solve(l - 1); ans2 = solve(r); printf("%lld\n", (ans2 - ans1 + mod) % mod); } return 0; }
原文:http://www.cnblogs.com/sagitta/p/4985429.html