light Oj 1172 二维DP+矩阵 UVa中等题

来源:互联网 发布:vc socket异步编程 编辑:程序博客网 时间:2024/06/01 12:54
 

light Oj 1172 二维DP+矩阵 UVa中等题

分类: light OJ 30人阅读 评论(0) 收藏 举报

lightOJ 矩阵题列表: http://lightoj.com/volume_problemcategory.php?user_id=8459&category=Matrix%20Exponentiation


花了1天多的时间,终于把lightOJ 矩阵题 切的只剩一题了, 最后一题只有1人AC,我想了不多不少的时间还是没有什么思路,所以先放一放吧。


先想想sorce很小的情况下如何做这题, 然后把sorce加大,套个矩阵就可以了。

因为dp是二维的,放入矩阵时把二维转变成一维。

我向来不喜欢把矩阵写成一个类,绝大部分人写的代码都是很费时间的,虽然看起来很爽很清楚,不过我熟练自己的写法,light oj基本很多矩阵题都是1A的,没有调试多久,时间也比很多人快。


[cpp] view plaincopy
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <algorithm>  
  4. #include <cmath>  
  5. using namespace std;  
  6. #define LL unsigned int  
  7. const int N = 160;  
  8. int b, s;  
  9. int n, X;  
  10. LL A[N][N], ans[N][N], B[N];  
  11.   
  12. void mult(LL a[][N], LL b[][N]) {       //矩阵乘法a = a*b  
  13.     LL c[N][N] = { 0 };  
  14.     int i, j, k;  
  15.     for (k = 0; k < n; k++)  
  16.         for (i = 0; i < n; i++) if (a[i][k])  
  17.             for (j = 0; j < n; j++)  
  18.                 c[i][j] += a[i][k] * b[k][j];  
  19.     for (i = 0; i < n; i++)  
  20.         for (j = 0; j < n; j++)  
  21.             a[i][j] = c[i][j];  
  22. }  
  23.   
  24.   
  25. inline int sqr(int x) {  
  26.     return x * x;  
  27. }  
  28.   
  29. int dp[38][8];  
  30. int dfs(int v, int e) {         // v为剩余的分数, e为结尾的数字  
  31.     if (!v)  
  32.         return 1;  
  33.     if(~dp[v][e]) return dp[v][e];  
  34.     dp[v][e] = 0;  
  35.     int &ret = dp[v][e], i;  
  36.     for (i = 0; i < b; i++)  
  37.         if (i != e) if(v >= sqr(i-e))  
  38.             ret += dfs(v - sqr(i - e), i);  
  39.     return ret;  
  40. }  
  41.   
  42. int main() {  
  43.     int i, j, k, cas;  
  44.     scanf("%d", &cas);  
  45.     for (int ca = 1; ca <= cas; ca++) {  
  46.         scanf("%d%d", &b, &s);  
  47.         printf("Case %d: ", ca);  
  48.         X = (b - 1) * (b - 1);  
  49.         n = X * b;  
  50.         if (b == 2) {  
  51.             puts("1");  
  52.             continue;  
  53.         }  
  54.   
  55.         memset(dp, -1, sizeof(dp));  
  56.         LL sum = 0;  
  57.         if (s <= X) {  
  58.             for (i = 1; i < b; i++)  //注意没有前导零  
  59.                 sum += dfs(s, i);  
  60.             printf("%u\n", sum);  
  61.             continue;  
  62.         }  
  63.   
  64.   
  65.         for (i = 1; i <= X; i++)  
  66.             for (j = 0; j < b; j++) {  
  67.                 B[(i - 1) * b + j] = dfs(i, j);  
  68.                 //记忆化搜索出     B[]初始状态       分数为1----(b-1)*(b-1), 以0---b结尾  
  69.             }  
  70.   
  71.         s -= X;  
  72.         //构造单位矩阵A  
  73.         for (i = 0; i < n; i++)  
  74.             for (j = 0; j < n; j++) {  
  75.                 ans[i][j] = (i == j);  
  76.                 A[i][j] = 0;  
  77.             }  
  78.   
  79.         for (i = 0; i < n - b; i++)  
  80.             A[i + b][i] = 1;  
  81.   
  82.         for (i = 1; i <= X; i++)  
  83.             for (j = 0; j < b; j++)  
  84.                 for (k = 0; k < b; k++) if(j != k)  
  85.                     if (sqr(j - k) == X+1-i) {  
  86.                         A[(i-1) * b + k][(X - 1) * b + j]++;  
  87.                     }  
  88.   
  89.         // ans = A^s  
  90.         while (s > 0) {  
  91.             if (s & 1) mult(ans, A);  
  92.             mult(A, A);  
  93.             s >>= 1;  
  94.         }  
  95.         for (i = 0; i < n; i++)  
  96.             for (j = n-b+1; j < n; j++)  
  97.                 sum += B[i] * ans[i][j];  
  98.             //取出以1-----b结尾的  数值   (题目的没有前导零可以转化成 结尾不为零)  
  99.         printf("%u\n", sum);  
  100.   
  101.     }  
  102.   
  103.     return 0;