洛谷 P6218 [USACO06NOV] Round Numbers S
题目
数位dp , 求范围内数的二进制形式中\(cnt_0 \ge cnt_1\)的个数
思路
数位dp , 肯定要记录长度和当前位
状态转移涉及 \(0\) 和 \(1\) 的个数 , 因此 \(f\) 中还应当有一维度为含 \(0\) 的数量
和P4999 烦人的数学作业类似 , 在 \(dp\) 过程中需要把已经经过的二进制记录 , 从而帮助判定当前的 \(0\) \(1\) 个数
dfs怎么做呢 ? 考虑记录路径上的\(lead , limit , cnt0, cnt1\)(也可以根据lead为false的位置确定总数) , 以\(cnt0 \ge cnt1\)为评判标准
代码
dp
#include<bits/stdc++.h>
using namespace std;
const int N = 33;
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
int a[N];
int f[N][N][2];
void init() {
f[1][1][0] = 1;
f[1][0][1] = 1;
for (int i =2; i< N ; i++) {
for (int j = 0; j<=i; j++) {
if (j>0)
f[i][j][0] = f[i-1][j-1][1] + f[i-1][j-1][0];
f[i][j][1] = f[i-1][j][0] + f[i-1][j][1];
}
}
}
int dp(int x) {
int cnt = 0,ans= 0;
while (x) {
a[++cnt] = x%2;
x>>=1;
}
int s0 = 0;
for (int i = cnt-1; i>0; i--){
if (a[i]) {
for (int j = 1; j<= i; j++)
if (s0 + j >= (cnt+1)>>1)
ans += f[i][j][0];
}
s0 += (a[i]==0);
if (s0>=cnt+1>>1 && i==1)
ans++;
}
for (int i= 1; i< cnt; i++) {
for (int j = i+1>>1; j<=i; j++) {
ans += f[i][j][1];
}
}
return ans;
}
int main() {
init();
int l =read(),r=read();
cout<<dp(r)-dp(l-1);
return 0;
}
dfs
#include<bits/stdc++.h>
using namespace std;
#define int long long int
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
int a[40];
int f[40][40][40];
int dfs(int pos,bool limit,bool lead,int cnt0,int cnt1) {
if (!pos) {
return cnt0 >= cnt1;
}
if (!limit && ! lead && f[pos][cnt0][cnt1] >=0)
return f[pos][cnt0][cnt1];
int up = limit?a[pos]:1;
int ans = 0;
for (int i = 0; i<= up; i++) {
ans += dfs(pos-1,limit&&i==up,lead &&i==0,cnt0+((i==0)&&!lead),cnt1+(i==1));
}
if (!limit && !lead) {
f[pos][cnt0][cnt1] = ans;
}
return ans;
}
int work(int x) {
int cnt = 0;
do {
a[++cnt] = x % 2;
x/=2;
}while (x);
return dfs(cnt,true,true,0,0);
}
signed main() {
memset(f,-1,sizeof f);
int l=read(),r=read();
cout<<work(r)-work(l-1)<<"\n";
return 0;
}

浙公网安备 33010602011771号