题意:给定进制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 ",ans); } }