标签:
/** 数位dp 求所有比n(1~10^6)小的书中二进制表示法“1”的个数是m的数的个数,dp[i][j]表示以i位数1的个数为j */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; const int maxn=50; int dp[maxn][maxn],bit[maxn]; int n,m; int dfs(int len,int num,int flag,int first) { if(len<0)return num==m; if(flag==0&&dp[len][num]!=-1) return dp[len][num]; int ans=0; int end=flag?bit[len]:1; for(int i=0;i<=end;i++) { int t=first&&(i==0); ans+=dfs(len-1,t?0:num+(i==1),flag&&i==end,t); } if(flag==0) dp[len][num]=ans; return ans; } int solve(int n) { int len=0; while(n) { bit[len++]=n&1; n>>=1; } return dfs(len-1,0,1,1); } int main() { int T; scanf("%d",&T); while(T--) { memset(dp,-1,sizeof(dp)); scanf("%d%d",&n,&m); printf("%d\n",solve(n-1)); } return 0; } /** 也可以用组合数来做:先将n用二进制表示sum[i]表示最高为到第i为有多少个1,这样遍历二进制位,若为1则置零,在剩下的i-1位中C(i-1,m-sum[i+1]) #include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <algorithm> using namespace std; int bit[35],ct; int sum[35]; int C[35][35]; //组合数 void init() { for(int i=1;i<32;i++) { C[i][0]=1; for(int j=1;j<i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j]; C[i][i]=1; } } void cal(int x) { memset(bit,0,sizeof(bit)); memset(sum,0,sizeof(sum)); ct=0; while(x) { bit[++ct]=x%2; x/=2; } for(int i=ct;i>=1;i--) if(bit[i]==1)sum[i]=sum[i+1]+1; else sum[i]=sum[i+1]; } int main() { int T; cin>>T; init(); while(T--) { int n,k; cin>>n>>k; cal(n); int ans=0; for(int i=ct;i>=1;i--) { if(bit[i]==1) { int tmp=k-sum[i+1] if(tmp==0) { ans++; break; } if(i-1>=tmp)ans+=C[i-1][tmp]; } } cout<<ans<<endl; } return 0; } */ /* 还有一个方法就是打表,哈哈~ */
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/45146015