P6429 [COCI2008-2009#1] JEZ 题解
原题链接
分析
看到题目的第一眼,发现这个人的走法比较鬼魅,但是我们考虑拆成一条条斜着走的路径。
对于当前
现在需要快速得到,对于一个数
具体实现可以看代码,总时间复杂度
Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 10;
int n, m, d[N];
ll k, tot, step;
inline int pos(int x, int i) {
return (x >> i - 1) & 1;//位运算找到 x 的第 i 位是 0 还是 1
}
inline int work(int x, int y) {//这里 x 和 y 是反着的
int ans = 0;
for (int i = 21; i; i--) {
if (!pos(x, i)) continue;
int cnt = 0;//记录 1 的个数
for (int j = i - 1; j; j--) cnt += pos(y, j);
ans += (1 << (i - 1 - cnt)) * ((1 << cnt) - 1);//0 的位子上随便选,1 的位子至少有一个 1
if (!pos(y, i)) continue;
for (int j = i - 1; j; j--)
if (pos(x, j)) ans += 1 << (j - 1);
ans++;//加上后面全部选 0 的
return ans;
}
return ans;
}
int main() {
cin >> n >> m >> k;
int l, r, pos = 1;
while (tot < k) {
int cnt = (pos > n) + (pos > m);//判断路径的长度如何变化
if (cnt == 0) step++;
if (cnt == 2) step--;
l = max(1, pos - m + 1);
r = min(n, pos);//寻找端点
step = min(step, k - tot);
tot += step;//最多走 k 步
if (pos & 1) d[r - step + 1]++, d[r + 1]--;
else d[l]++, d[l + step - 1 + 1]--;//差分
pos++;//奇偶性判断走的方向
}
ll ans = 0;
for (int i = 1; i <= n; i++, d[i] += d[i - 1])
if (d[i]) ans += work(d[i] - 1, i - 1);//注意值域是从 0 开始的
cout << k - ans;//总数减去不合法数
return 0;
}