洛谷P6218

感受此題是P4317 花神的數論題的變形版ios


Description

求一段區間內二進制中 \(0\) 的個數不小於 \(1\) 的個數的數的個數spa


Solution

數位 DPcode

先考慮狀態轉移方程式,如何處理處全部數ip

\(f[i][j][k]\) 表示枚舉到第 \(i\) 位,數字爲 \(j\),此時二進制中 \(1\) 的個數爲 \(k\)get

顯然有string

\[f[i][0][j]=\sum_{k=0}^if[i-1][1][k]+f[i-1][0][k] \]

\[f[i][1][j]=\sum_{k=1}^if[i-1][0][k-1]+f[i-1][1][k-1] \]

與花神的數論題是同樣的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]\)


Code

#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;
}
相關文章
相關標籤/搜索