UVA11651Krypton Number System(DP+矩阵快速幂)
来源:互联网 发布:实惠猪软件多少钱 编辑:程序博客网 时间:2024/06/06 19:56
由于CSDN编辑的不方便,所以给出一篇别人的讲解:http://www.cnblogs.com/AOQNRMGYXLMV/p/5256508.html
但是他的转移出现了错误。正确的矩阵相乘应该是这样
题目意思是给定一个进制base和一个score,问在该进制下有多少数满足下列条件:相邻两个数字不相同,前缀不能为0,所有相邻数字的差的平方和位score,所有数字都是整数。
这个题目难度主要集中在找递推式子,一开始确实没有思路,看了一个人的博客,知道用DP和矩阵快速幂做,试着去推DP的方程
有dp[i][j]表示当score = i时数字末尾为j的数字的个数。
我们拿4进制简单推一下,首先初始化显然有,然后继续推score = 1的情况:,继续推score = 2的情况:,继续推score = 3的情况:,继续推score =4的情况:
,我说,这样一直递推到8就可以了,为什么呢?因为如果我们把0作为第一个节点,那么0下一次最大只能到达,也就是9,这样0-8就形成了一个循环节。显然0 -> 9, 1 -> 10 ... 8 -> 17都是一样的递推式子。这样我们就得到了递推的关系式,然后就可以用矩阵快速幂优化计算,最后就能得到答案。
到只需要将第一个矩阵的后4 * 8项依次往前平移4项,然后第二个矩阵最后四项的则需要利用上面的递推关系式得到。我们只需要得到后,利用矩阵快速幂就可以求得任意一项的值
我的心得体会:在初始化 这个dp数组时候有两种初始化方法,也意味着两种不同的理解。第一种是上面的这样,还有一种就是dp[0][..]全部初始化为1,然后计算答案的时候就需要从当score为n时最后一位为1到base-1开始相加。可以这样理解,这样初始化意味着允许出现前导零,但数的最后一位不能是零,这和题目要求其实是一样的作用。
还有就是循环节,因为每次增加一个数score最大只能增加,所以每轮计算(n-1)*(n-1)个score的模式是一样的。代码对于下标的各种用法,还是很有技巧性的。最后还有一点在代码的注释中。。
第一种初始化dp的代码:
#include<iostream>#include<cstring>#include<cstdio>using namespace std;typedef unsigned int LL;const int maxn = 155;int n, m, sz;struct Matrix{ LL mat[maxn][maxn]; Matrix () { memset(mat, 0, sizeof(mat)); } Matrix operator * (const Matrix& other) const { Matrix tem; for(int i = 0; i < sz; i++) for(int j = 0; j < sz; j++) if(mat[i][j]) for(int k = 0; k < sz; k++) tem.mat[i][k] += mat[i][j] * other.mat[j][k]; return tem; }};Matrix fast_mod(Matrix base, int power){ Matrix ans; for(int i = 0; i < sz; i++) ans.mat[i][i] = 1; while(power) { if(power&1) ans = ans * base; base = base * base; power >>= 1; } return ans;}LL a[maxn], dp[30][10];int main(){ int T; scanf("%d", &T); for(int kase = 1; kase <= T; kase++) { scanf("%d%d", &n, &m); printf("Case %d: ", kase); int N = (n-1) * (n-1) * n; memset(dp, 0, sizeof(dp)); for(int i = 1; i < n; i++) dp[0][i] = 1; for(int i = 0; i < (n-1)*(n-1); i++) { for(int j = 0; j < n; j++) { for(int k = 0; k < n; k++) { int d = (k - j) * (k - j); if(!d || i + d >= (n-1)*(n-1)) continue; dp[i+d][k] += dp[i][j]; } } } if(m < (n-1)*(n-1)) { LL ans = 0; for(int i = 0; i < n; i++) ans += dp[m][i]; printf("%u\n", ans); continue; } sz = N; int s = (n - 1) * (n - 1); for(int i = 0; i < (n - 1) * ( n - 1); i++) for(int j = 0; j < n; j++) a[i*n+j] = dp[i][j]; Matrix base; for(int i = n; i < N; i++) base.mat[i-n][i] = 1; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) { int d = (j - i) * (j - i); base.mat[N - n + i][n * (s - d) + j] = 1; //之所以是n * (s - d) + j,因为s-d意味着是从哪个数转移过来的,所以乘n就很好理解了,+j纯属下标的理解 } base = fast_mod(base, m - (n-1)*(n-1) + 1); LL ans = 0; for(int i = N - n; i < N; i++) for(int j = 0; j < N; j++) ans += base.mat[i][j] * a[j]; printf("%u\n", ans); } return 0;}
第二种初始化代码:(结构体内各种重载!!)
#include <stdio.h>#include <string.h>const unsigned long long mod = 1LLU<<32;struct Matrix {unsigned long long v[150][150];int row, col; // row x colMatrix(int n, int m, long long a = 0) {memset(v, 0, sizeof(v));row = n, col = m;for(int i = 0; i < row && i < col; i++)v[i][i] = a;}Matrix operator*(const Matrix& x) const {Matrix ret(row, x.col);for(int i = 0; i < row; i++) {for(int k = 0; k < col; k++) {if (v[i][k])for(int j = 0; j < x.col; j++) {ret.v[i][j] += v[i][k] * x.v[k][j],ret.v[i][j] %= mod;}}}return ret;}Matrix operator^(const int& n) const {Matrix ret(row, col, 1), x = *this;int y = n;while(y) {if(y&1)ret = ret * x;y = y>>1, x = x * x;}return ret;}};int main() {int testcase, cases = 0, base, score;scanf("%d", &testcase);while(testcase--) {scanf("%d %d", &base, &score);printf("Case %d: ", ++cases);int N = (base - 1) * (base - 1);unsigned long long dp[64][64] = {};for (int i = 0; i <= N; i++)dp[0][i] = 1;for (int i = 0; i < N; i++) {for (int j = 0; j < base; j++) {for (int k = 0; k < base; k++) {int d = (j - k) * (j - k);if (i + d > N || j == k)continue;dp[i+d][k] += dp[i][j];dp[i+d][k] %= mod;}}}if (score <= N) {unsigned long long ret = 0;for (int i = 1; i < base; i++)ret = (ret + dp[score][i])%mod;printf("%llu\n", ret);continue;}int r, c;r = c = (base - 1) * (base - 1) * base;Matrix x(r, c), y(c, 1);for (int i = 1; i <= N; i++)for (int j = 0; j < base; j++)y.v[(i-1) * base+j][0] = dp[i][j];for (int i = base; i < r; i++)x.v[i - base][i] = 1;for (int i = 0; i < base; i++) {for (int j = 0; j < base; j++) {if (i == j)continue;int d = N - (i - j) * (i - j);x.v[(N-1)*base + i][d*base + j] = 1;}}Matrix z = (x ^ (score - N)) * y;unsigned long long ret = 0;for (int i = 1; i < base; i++)ret = (ret + z.v[(N-1) * base + i][0])%mod;printf("%llu\n", ret);}return 0;}
- UVA11651Krypton Number System(DP+矩阵快速幂)
- UVA 11651 - Krypton Number System(DP+矩阵快速幂)
- zoj3690--Choosing number(dp,矩阵快速幂)
- UVA 11651 Krypton Number System(矩阵加速DP)
- uva 11651 - Krypton Number System(矩阵快速幂)
- uva Krypton Number System dp+矩阵优化
- hdu6198 number number number(找规律+矩阵快速幂)
- HDU 6198 number number number(规律+矩阵快速幂)
- HDU-6189 number number number(矩阵快速幂)
- HDU 6198number number number(矩阵快速幂)
- hdu6198 number number number(矩阵快速幂模板题)
- HDU6198 number number number 矩阵快速幂
- BNUOJ28891 Choosing number(矩阵快速幂)
- HDU1005 - Number Sequence (矩阵快速幂)
- Number Sequence 矩阵快速幂
- [HDU2604]Queuing(dp+矩阵快速幂)
- 骨牌问题(DP+矩阵快速幂)
- POJ3734Blocks DP&&矩阵快速幂
- java接口和类的区别Java 接口
- LUT函数的使用——opencv
- ubuntu 16.04安装WPS总结
- 一天一条Linux指令-make
- 【UML】--初识
- UVA11651Krypton Number System(DP+矩阵快速幂)
- Django框架学习-Model篇
- 坚持#第89天~胡晨晨会给予我力量!
- 【机器学习】【计算机视觉】数据挖掘测试数据集大全
- vim 编译器的使用
- machine learning 四要素
- 如何写出面试官欣赏的Java单例
- LeetCode 70. Climbing Stairs
- c语言的基本数据类型