UVALive 7271 A Math Problem 【數位dp計數】
阿新 • • 發佈:2019-01-14
資料問題:
這題UVA上的資料應該是有問題,沒人AC,可以在hihocode上提交,http://hihocoder.com/problemset/problem/1259?sid=949910
解題思路:
分析3 × f(n) × f(2n + 1) =f(2n) × (1 + 3f(n)), f(2n) < 6 × f(n)可以發現,3*f(n),3*f(n)+1互素。又有限制條件f(2n)<6*f(n),可以推出f(2n)=3*f(n),f(2n+1)=3*f(n)+1。寫出前幾項:
f(1)=1,f(2)=3,f(3)=4,f(4)=9,f(5)=10,f(6)=12,f(7)=13,f(8)=27,f(9)=28...
f(1) = f(0012)=1=0013,f(2)=f(0102)=3=0103,f(3)=f(011)=4=0113…可以發現f(n)的功能其實就是把對應的n的二進位制表示當作三進位制來算。發現這個關係後,可以用數位dp算出1-n範圍內mod K餘數為r的數的個數,dp[p][r]表示從第p位開始餘數為r的數的個數。轉移為dp[p][r]+=dp[p-1][r-i*3p]。
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<map> #include<string> #include<queue> #include<vector> #include<list> #include<bitset> //#pragma comment(linker,"/STACK:1024000000,1024000000") using namespace std; typedef long long ll; #define INF 0x3f3f3f3f ll n; int K; int dig[100]; int fac[100]; ll dp[65][65537]; ll dfs(int p,int r,int is) { if(p==-1) { return r==0; } ll res=0; if(!is&&dp[p][r]!=-1) return dp[p][r]; int up=is?dig[p]:1; for(int i=0;i<=up;i++) { res+=dfs(p-1,(r-i*fac[p]+K)%K,is==1&&i==up); } if(!is) dp[p][r]=res; return res; } void solve() { memset(dp,-1,sizeof dp); long long tmp=n; int len=0; while(tmp) { dig[len++]=tmp%2; tmp/=2; } ll ans=0; for(int i=0;i<K;i++) ans^=dfs(len-1,i,1)-(i==0); printf("%lld\n",ans); } int main() { int t; fac[0]=1; scanf("%d",&t); while(t--) { scanf("%lld%d",&n,&K); for(int i=1;i<100;i++) fac[i]=fac[i-1]*3%K; solve(); } return 0; }