POJ 3252 Round Numbers
数位DP。dp[i][j][k]表示有i位,首位为j,有k个1的二进制数字有几个。
很容易写出递推式:
dp[i][0][k]+=dp[i-1][0][k];
dp[i][0][k]+=dp[i-1][1][k];
dp[i][1][k]+=dp[i-1][0][k-1];
dp[i][1][k]+=dp[i-1][1][k-1];
之后就进行统计,容斥减一下就是答案了
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; //dp[i][j][k]表示有i位,首位为j,有k个1的数量 int dp[35][5][35]; int Start,Finish; int p[35]; int tot; void init() { memset(dp,0,sizeof dp); dp[1][0][0]=1; dp[1][1][1]=1; for(int i=2;i<=32;i++) { for(int j=0;j<=1;j++) { for(int k=0;k<=i;k++) { if(j==0) { dp[i][0][k]+=dp[i-1][0][k]; dp[i][0][k]+=dp[i-1][1][k]; } else { if(k-1>=0) { dp[i][1][k]+=dp[i-1][0][k-1]; dp[i][1][k]+=dp[i-1][1][k-1]; } } } } } } int f(int x) { tot=1; while(x) { p[tot++]=x%2; x=x/2; } tot--; int res=0; for(int i=1;i<tot;i++) for(int k=0;k<=i;k++) if(k<=i-k) res=res+dp[i][1][k]; int one=1,zero=0; for(int i=tot-1;i>=1;i--) { if(p[i]==0) {zero++;continue;} for(int k=0;k<=i;k++) if(one+k<=zero+i-k) res=res+dp[i][0][k]; one++; } return res; } int main() { init(); while(~scanf("%d%d",&Start,&Finish)) printf("%d\n",f(Finish+1)-f(Start)); return 0; }