COJ1160[一本通 5.3 例 1」Amount of Degrees
阿新 • • 發佈:2018-12-05
試題描述 |
求給定區間[X,Y]中滿足下列條件的整數個數:這個數恰好等於K個互不相等的B的整數次冪之和。例如,設X=15,Y=20,K=2,B=2,則有且僅有下列三個數滿足題意: |
輸入 |
第一行包含兩個整數X和Y,接下來兩行分別包含整數K和B。 |
輸出 |
只包含一個整數,表示滿足條件的數的個數。 |
輸入示例 |
15 20 2 2 |
輸出示例 |
3 |
其他說明 |
資料範圍:對於全部資料,1 <= X <= Y <= 2^31−1,1 <= K <= 20,2 <= B <= 10。 |
思路:
這是一道奇怪的數位DP
第一步,我們要把這個輸入的十進位制轉化成一個b進位制數
首先我們想到2進位制的情況,設dp[i][j]表示後i位有j個1
顯然,dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
然後查詢時,我們只需要知道當前數字%2是否為0
將已經取了的數字1個數記為t
若為0,說明這一位無法進行操作
若為1,固定這一位是1,問題變成了求
(1)取(1<<i)這個1,sum=在a-(1<<i)中取k-t-1個1
(2)不取取(1<<i)這個1,sum=在a中不取(1<<i)取k-t個1
兩個和起來即為答案
即sum=cnt(a-(1<<i),k-t-1)+dp[i-1][k-t]的和(前者沒有說明好說的,後者下一層隨便搞都不會超過(1<<i),所以直接套用dp即可)
如果最後發現k==t,直接退出遞迴
但是我們發現,如果k==t時我們最後一次直接退出返回值是0,而實際上應該是1
所以最後sum應加上1
推己及彼,舉壹反叄,我們發現任何進位制,對於這一位為0時都無法做運算
對於這一位為1時,和二進位制的做法相同
B進位制和二進位制唯一的區別是當這一位大於0時,我們發現從這一位隨便搞都無法超過x^i(x為這一位的數字)
所以此時只需要加上一個dp[i][k-t],然後退出迴圈即可
好了
上程式碼
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dwn(i,a,b) for(int i=a;i>=b;i--) using namespace std; int dp[32][25],x,y,k,b,tot,p[32]; int cnt(int a){ tot=0;int sum=0,t=0; while(a){ p[++tot]=a%b; a/=b; } dwn(i,tot,1){ if(t==k) break; if(p[i]==1) sum+=dp[i-1][k-t],t++; else if(p[i]){sum+=dp[i][k-t]; break;} } if(t==k) sum++; return sum; } int main(){ scanf("%d%d%d%d",&x,&y,&k,&b); rep(i,0,31) dp[i][0]=1; rep(i,1,31) rep(j,1,k) dp[i][j]=dp[i-1][j]+dp[i-1][j-1]; printf("%d",cnt(y)-cnt(x-1)); return 0; }