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

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


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


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

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

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


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL unsigned int
const int N = 160;
int b, s;
int n, X;
LL A[N][N], ans[N][N], B[N];

void mult(LL a[][N], LL b[][N]) {  		//矩阵乘法a = a*b
    LL c[N][N] = { 0 };
    int i, j, k;
    for (k = 0; k < n; k++)
        for (i = 0; i < n; i++) if (a[i][k])
            for (j = 0; j < n; j++)
                c[i][j] += a[i][k] * b[k][j];
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            a[i][j] = c[i][j];
}


inline int sqr(int x) {
    return x * x;
}

int dp[38][8];
int dfs(int v, int e) {			// v为剩余的分数, e为结尾的数字
    if (!v)
        return 1;
    if(~dp[v][e]) return dp[v][e];
    dp[v][e] = 0;
    int &ret = dp[v][e], i;
    for (i = 0; i < b; i++)
        if (i != e) if(v >= sqr(i-e))
            ret += dfs(v - sqr(i - e), i);
    return ret;
}

int main() {
    int i, j, k, cas;
    scanf("%d", &cas);
    for (int ca = 1; ca <= cas; ca++) {
        scanf("%d%d", &b, &s);
        printf("Case %d: ", ca);
        X = (b - 1) * (b - 1);
        n = X * b;
        if (b == 2) {
            puts("1");
            continue;
        }

        memset(dp, -1, sizeof(dp));
        LL sum = 0;
        if (s <= X) {
            for (i = 1; i < b; i++) 	//注意没有前导零
                sum += dfs(s, i);
            printf("%u\n", sum);
            continue;
        }


        for (i = 1; i <= X; i++)
            for (j = 0; j < b; j++) {
                B[(i - 1) * b + j] = dfs(i, j);
                //记忆化搜索出     B[]初始状态       分数为1----(b-1)*(b-1), 以0---b结尾
            }

        s -= X;
        //构造单位矩阵A
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++) {
                ans[i][j] = (i == j);
                A[i][j] = 0;
            }

        for (i = 0; i < n - b; i++)
            A[i + b][i] = 1;

        for (i = 1; i <= X; i++)
            for (j = 0; j < b; j++)
                for (k = 0; k < b; k++) if(j != k)
                    if (sqr(j - k) == X+1-i) {
                        A[(i-1) * b + k][(X - 1) * b + j]++;
                    }

        // ans = A^s
        while (s > 0) {
            if (s & 1) mult(ans, A);
            mult(A, A);
            s >>= 1;
        }
        for (i = 0; i < n; i++)
            for (j = n-b+1; j < n; j++)
                sum += B[i] * ans[i][j];
        	//取出以1-----b结尾的  数值   (题目的没有前导零可以转化成 结尾不为零)
        printf("%u\n", sum);

    }

    return 0;
}


你可能感兴趣的:(light Oj 1172 二维DP+矩阵 UVa中等题)