Krypton Number System uva 11651(dp+矩阵快速幂)

题目链接

题意:给定进制base,和分数score,求在base进制下,有多少个数的值为score,要求不能有连续相同的数字以及前导0.计算一个数的值即为相邻两位数的差平方的和。

思路:因为score很大,所以直接dp肯定超时,但是即使对于base=6的情况,每次新添一个数score最大增加25(0-5),所以用dp[i][j]预处理出base平方以内的总数,然后用矩阵快速幂计算。

#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
const int maxn=160;
const ll mod=(1ull<<32);
struct Marix{//矩阵
    ll mo[maxn][maxn],n;
    Marix(){}
    Marix(int _n){
        n=_n;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++) mo[i][j]=0;
        }
    }
};
Marix mul(Marix a,Marix b){//矩阵乘法
    Marix res=Marix(a.n);
    for(int i=0;i<a.n;i++){
        for(int j=0;j<a.n;j++){
            for(int k=0;k<a.n;k++){
                int tmp=(ll)a.mo[i][k]*b.mo[k][j]%mod;
                res.mo[i][j]=(res.mo[i][j]+tmp)%mod;
            }
        }
    }
    return res;
}
Marix powMod(Marix a,int n){//矩阵快速幂
    Marix nul;
    nul=Marix(a.n);
    for(int i=0;i<nul.n;i++){
        nul.mo[i][i]=1;
    }
    while(n){
        if(n&1) nul=mul(nul,a);
        a=mul(a,a);
        n>>=1;
    }
    return nul;
}
ll n,dp[maxn][maxn],k,m;
int main()
{
    int t;
    int u=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%llu%llu",&m,&k);
        printf("Case %d: ",++u);
        n=(m-1)*(m-1);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=n;i++)
        {
            dp[0][i]=1;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                for(int k=0;k<m;k++)
                {
                    int f=(j-k)*(j-k);
                    if(i+f>n||f==0)
                    continue;
                    dp[i+f][j]=(dp[i+f][j]+dp[i][k])%mod;
                }
            }
        }
        ll ans=0;
        if(k<=n)
        {
            for(int i=1;i<m;i++)
            {
                ans=(ans+dp[k][i])%mod;
            }
        }
        else
        {
            Marix ret=Marix(n*m);
            for(int i=1;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    ret.mo[(i-1)*m+j][0]=dp[i][j];
                }
            }
            ret=powMod(ret,k-n);
            for(int i=1;i<m;i++)
            {
                ans=(ans+ret.mo[(n-1)*m+i][0])%mod;
            }
        }
        printf("%llu\n",ans);
    }
 } 

 

posted @ 2020-09-29 16:00  Ldler  Views(107)  Comments(0Edit  收藏  举报