LuoguP6218 [USACO06NOV] Round Numbers S
Posted shadowflowhyc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LuoguP6218 [USACO06NOV] Round Numbers S相关的知识,希望对你有一定的参考价值。
题目描述
如果一个正整数的二进制表示中,(0)的数目不小于(1)的数目,那么它就被称为「圆数」。
例如,(9)的二进制表示为(1001),其中有(2)个(0)与(2)个(1)。因此,(9)是一个「圆数」。
请你计算,区间([l,r])中有多少个「圆数」。
输入格式
一行,两个整数(l)和(r)。
输出格式
一行,一个整数,表示区间([l,r])中「圆数」的个数。
样例
输入:(2 12) 输出: (6)
思路
显然这道题又是一道数位DP。但是这个题的难点和特殊之处就在于它是在二进制下处理的。这就需要我们重新揣度此题的状态。
设(f[i][j][k])表示一个有(i)位,且其中包括(j)个(1),且从右往左数第(i)个数是(k)的圆数的个数。这个如何转移呢?
显然的是,若(j < i), (f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]),若(j !=0), 则(f[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1]) (这个感性理解一下?)
最后就分成两种情况处理:
1.将位数小于cnt位的圆数累加到答案中
2.和其他数位DP类似,考虑用添数的方法解决问题。若当前遍历到该位为(1),那么就存在该位为(0)的情况,这时候再枚举(1)的位数,考虑还是否能构成圆数,若能构成,累加答案即可。
最后前缀和统计答案即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
int l, r;
ll f[35][35][2];
inline int read(void){
int f = 1, x = 0;char ch;
do{ch = getchar();if(ch==‘-‘)f = -1;} while (ch < ‘0‘ || ch > ‘9‘);
do{ x = x * 10 + ch - ‘0‘;ch = getchar();} while (ch >= ‘0‘ && ch <= ‘9‘);
return f * x;
}
inline void _init(void){
f[1][0][0] = 1, f[1][1][1] = 1;//初始化
for (int i = 2; i <= 32;++i){
for (int j = 0; j <= i;++j){
if(j<i) f[i][j][0] = f[i - 1][j][0] + f[i - 1][j][1];//若既有0又有1或只有0
if(j) f[i][j][1] = f[i - 1][j - 1][0] + f[i - 1][j - 1][1];//若有1或全部是1
}
}
return;
}
inline ll calc(int x){
int bn[35], cnt = 0;
ll res = 0;
if(x==0) return 1;
while(x){
bn[++cnt] = x & 1;
x >>= 1;
}//二进制拆分
for (int i = 1; i < cnt;++i){
for (int j = 0; j <= (i >> 1); ++j)
res += f[i][j][1];
}//统计小于cnt位的圆数,(i>>1)这个就是保证了所得的数一定为圆数
int s0 = 0, s1 = 1;//s1一定要赋值为1,因为无论如何我们讨论的数都是大于1的(为0的情况在开头就舍掉了)
for (int i = cnt - 1; i >= 1;--i){
if(bn[i]) for (int j = 0; j <= i;++j){
if(s0+i-j>=s1+j) res += f[i][j][0];//已确定的0的个数+枚举的0的个数>=已确定的1的个数+枚举的1的个数
}// s0 + i - j >= s1 + j
bn[i] ? ++s1 : ++s0;
}
return res;
}
int main(){
l = read(), r = read();
_init();
printf("%lld
", calc(r + 1) - calc(l));
return 0;
}
以上是关于LuoguP6218 [USACO06NOV] Round Numbers S的主要内容,如果未能解决你的问题,请参考以下文章
[luoguP2886] [USACO07NOV]牛继电器Cow Relays(矩阵)
[luoguP3092] [USACO13NOV]没有找零No Change(状压DP + 二分)
[luoguP2915] [USACO08NOV]奶牛混合起来Mixed Up Cows(DP)
[luoguP2885] [USACO07NOV]电话线Telephone Wire(DP + 贪心)