感受此題是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; }