洛谷 P6218
题目链接: P6218 [USACO06NOV] Round Numbers S
题目大意
详见题目
solution
有一个显而易见的结论
发现 \(ans_{l, r} = ans_{1. r} - ans_{1, l - 1}\)
那只需要处理 \(1 - r\) 的即可
设 \(f_{i, j, k}\) 表示长度为 \(i\) 最高位为 \(j\) 的且 \(1\) 的个数为 \(k\) 的数的个数
- \(j=1, \ f_{i, j, k} = \sum\limits_{p = 0}^{p \leqslant 1}\sum\limits_{k = 0}^{k \leqslant i} f_{i - 1, p, k - 1}\)
- \(j=0, \ f_{i, j, k} = \sum\limits_{p = 0}^{p \leqslant 1}\sum\limits_{k = 0}^{k \leqslant i} f_{i - 1, p, k}\)
对于\(ans_{1, r}\) 我们可以采用以下策略 :
设 \(len\) 为 \(r\) 的位数, \(a_{len}\) 为 \(r\) 的每一位
- 对于首位为 \(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]\)
那么答案就是 \(ans_{1, r} - ans_{1, l - 1}\)
Code:
/**
* Author: Aliemo
* Data:
* Problem:
* Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define rr register
#define inf 1e9
#define MAXN 100010
using namespace std;
inline int read() {
int s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
int l, r, len;
int f[50][2][50], a[50];
inline void init() {
f[1][1][1] = 1, f[1][0][0] = 1;
for (rr int i = 2; i < 35; i++)
for (rr int j = 0; j <= 1; j++)
for (rr int k = 0; k <= i; k++)
for (rr int p = 0; p <= 1; p++)
if (!j) f[i][j][k] += f[i - 1][p][k];
else if (k) f[i][j][k] += f[i - 1][p][k - 1];
}
inline int solve(int x) {
memset(a, 0, sizeof a);
len = 0;
while (x) {
a[++len] = x % 2;
x /= 2;
}
int ans = 0, cnt1 = 1, cnt0 = 0;
for (rr int i = len - 1; i >= 1; i--) {
int x = a[i];
if (x) {
for (rr int j = 0; j <= len / 2 - cnt1; j++) {
ans += f[i][0][j];
// cout << ans << "\n";
}
}
cnt1 += x;
cnt0 += (x == 0);
if (cnt0 >= cnt1 && i == 1) ans++;
}
for (rr int i = 1; i < len; i++)
for (rr int j = 0; j <= i / 2; j++)
ans += f[i][1][j];
return ans;
}
signed main() {
init();
l = read(), r = read();
cout << solve(r) - solve(l - 1);
}
时间会刺破青春表面的彩饰,会在美人的额上掘深沟浅槽;会吃掉稀世之珍!天生丽质,什么都逃不过他那横扫的镰刀。
博主写的那么好,就不打赏一下么(打赏在右边)