[COCI2008-2009#1] JEZ 题解
题意
给定一个由
然后一个人按照下图规律从
思路
先假设
因为人是斜着走的,我们可以直接从斜向考虑,对于一条斜线,上面所有的
因为异或的性质,1 ,那么 1,如果某一位为 0 ,那么 0 要么同为 1,如果两个位置同为 1,而且在 0 ,因为相加进位的关系,1 才能保证 0,同理,如果左边一位为 0, 0。
也就是说对于 0,那么 0,否则 1,记 1 的数目,对于 1 ,故这条斜线上灰色格子的数量最大值为
而当我们从 1 在 1 ,然后将 0 的位置去掉,此时得到的数字就是在范围内你每一位选择选或者不选得到的答案数,将这个数加上一,也就是全不选的操作,就是路径上灰色格子的数目了。
int Fun(int y, int x) {
int num = 0, res = 1;
while (y) { //找到y中每一位1并记录对应的值
if (y & 1) {
Bit[num] = res;
num++;
}
y >>= 1;
res <<= 1;
}
int tmp = 0; // tmp记录格子数
for (int i = num - 1; i >= 0; --i) {
if (x - Bit[i] >= 0) { //这里可以找到最大的灰色格子位置
x -= Bit[i];
tmp = tmp | (1 << (i)); //因为记录了y中每一位1,所以说直接可以求出最终答案数
}
}
++tmp; //最后加上全不选的答案
return tmp;
}
这样我们就可以求出路径上每一条走满的斜线上灰色格子数,对于最后可能走不满的斜线,可以直接暴力求解,也可以做差求解即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int Bit[128];
int Fun(int y, int x) {
int num = 0, res = 1;
while (y) { //找到y中每一位1并记录对应的值
if (y & 1) {
Bit[num] = res;
num++;
}
y >>= 1;
res <<= 1;
}
int tmp = 0; // tmp记录格子数
for (int i = num - 1; i >= 0; --i) {
if (x - Bit[i] >= 0) { //这里可以找到最大的灰色格子位置
x -= Bit[i];
tmp = tmp | (1 << (i)); //因为记录了y中每一位1,所以说直接可以求出最终答案数
}
}
++tmp; //最后加上全不选的答案
return tmp;
}
signed main() {
int r, c, k;
int Now = 0;
int ans = 0;
bool dirt = true;
scanf("%lld %lld %lld", &r, &c, &k);
if (c < r) {
swap(c, r);
dirt = false;
}
--r;
--c;
for (int i = 0; i <= c; ++i) { //分两部分解决,第一部分是从顶部开始的斜线
int step = min(r, i) + 1;
int cnt = Fun(i, min(r, i));
if (Now + step < k) {
Now += step;
ans += cnt;
} else {
if (dirt) {
int x = min(i, r);
int y = i - x;
while (Now < k) {
if (x + y == (x ^ y))
++ans;
x--;
y++;
++Now;
}
} else {
int x = 0;
int y = i;
while (Now < k) {
if (x + y == (x ^ y))
++ans;
x++;
y--;
++Now;
}
}
break;
}
dirt ^= 1;
}
if (Now == k) {
printf("%lld\n", ans);
return 0;
}
for (int i = 1; i <= r; ++i) { //第二部分是从右侧开始的斜线
int step = r - i + 1;
int cnt = Fun(c + i, r) - Fun(c + i, i - 1);
if (Now + step < k) {
Now += step;
ans += cnt;
} else {
if (dirt) {
int x = r;
int y = c - (r - i);
while (Now < k) {
if (x + y == (x ^ y))
++ans;
x--;
y++;
++Now;
}
} else {
int x = i;
int y = c;
while (Now < k) {
if (x + y == (x ^ y))
++ans;
x++;
y--;
++Now;
}
}
break;
}
dirt ^= 1;
}
printf("%lld\n", ans);
}