ural 1057 Amount of degrees 【數位dp】
阿新 • • 發佈:2017-08-01
ont ++ algorithm printf pre turn blog _id 數位dp
題意:求(x--y)區間轉化為 c 進制 1 的個數為 k 的數的出現次數。
分析:發現其滿足區間減法,所以能夠求直接求0---x 的轉化為 c 進制中 1 的個數為k的數的出現次數。
首先用一個數組f【i】【j】:表示前 i 位中有 j 位為 1 的個數。
能夠通過方程 f【i】【j】 = f【i-1】【j】 + f【i-1】【j-1】來預處理出來。
對於要求的答案,我們能夠借助樹來求。
假如13 。2進制,有3個1 。轉化為2進制 1101
能夠借助於一個二進制的表示的樹來求。
AC代碼:
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <map> #include <string> #include <iostream> #include <cmath> using namespace std; #define Del(a,b) memset(a,b,sizeof(a)) typedef long long LL; const double esp = 1e-10; const int N = 50; int f[N][N]; //f[i][j] 前i個中選j個1的個數 void isit() { f[0][0] = 1; for(int i=1;i<33;i++){ f[i][0] = f[i-1][0]; for(int j=1;j<=i;j++) f[i][j] = f[i-1][j] + f[i-1][j-1]; } } int solve(int x,int k,int c) { vector<int> v; while(x) { v.push_back(x%c); x/=c; } int cnt = 0,ans = 0; for(int i=v.size()-1;i>=0;i--) { if(v[i]==1) //為1,則依次求解 { ans+=f[i][k-cnt]; cnt++; if(cnt==k) break; } else if(v[i]>1) //假如大於1的話。相當於全部的位有能夠為1,所以直接求解跳出 { ans += f[i+1][k-cnt]; break; } } if(cnt==k) ans++; return ans; } int main() { isit(); int x,y,k,c; while(~scanf("%d%d%d%d",&x,&y,&k,&c)) { printf("%d\n",solve(y,k,c)-solve(x-1,k,c)); } return 0; }
ural 1057 Amount of degrees 【數位dp】