感受此题是P4317 花神的数论题的变形版ios
求一段区间内二进制中 \(0\) 的个数不小于 \(1\) 的个数的数的个数spa
数位 DPcode
先考虑状态转移方程式,如何处理处全部数ip
设 \(f[i][j][k]\) 表示枚举到第 \(i\) 位,数字为 \(j\),此时二进制中 \(1\) 的个数为 \(k\)get
显然有string
与花神的数论题是同样的it
另外一部分,考虑答案的统计io
显然,对于 \(ans_{l,r}\),能够转化为 \(ans_{1,r}-ans_{1,l-1}\)class
把最高位上的数与最高位如下的分开统计stream
因为存在原数定义的限制,咱们对于 \(ans_{1,V}\) 可用以下方法处理
设 \(len\) 为 \(V\) 的位数, \(a_i\) 为 \(V\) 的第 \(i\) 位
对于首位为 \(1\) 且前面有 \(cnt1\) 个 \(1\) 的 \(f\),
\(res+=f[i][0][j],i\in[1,len),j\in[0,len/2-cnt1]\)
对于首位为 0 的 f,
\(res+=f[i][1][j],i\in[1,len),j\in[0,i/2]\)
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #define maxn 10000100 //#define int long long using namespace std; int f[50][2][50],a[50]; int l,r; int read(){ int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar(); return s*w; } void init(){ f[1][1][1]=1;f[1][0][0]=1; for(int i=2;i<35;i++) for(int j=0;j<=1;j++) for(int k=0;k<=i;k++) for(int s=0;s<=1;s++){ if(!j)f[i][j][k]+=f[i-1][s][k]; if(j&&k) f[i][j][k]+=f[i-1][s][k-1]; } } int solve(int x){ memset(a,0,sizeof a); int len=0,ans=0,cnt1=1,cnt0=0; while(x){a[++len]=x%2;x/=2;} for(int i=len-1;i>=1;i--){ if(a[i]) for(int j=0;j<=len/2-cnt1;j++) ans+=f[i][0][j]; cnt1+=a[i];cnt0+=(a[i]==0); if(cnt0>=cnt1&&i==1) ans++; } for(int i=1;i<len;i++) for(int j=0;j<=i/2;j++) ans+=f[i][1][j]; return ans; } int main(){ init(); l=read();r=read(); printf("%d",solve(r)-solve(l-1)); return 0; }