GMOJ 7237. 【USACO 2021 February Contest, Gold】Problem 3 Count the Cows题解
题目自己看。
Solution
打个表
容易发现这个01矩阵有一定规律
假设初始矩阵为
X
X
X
每次把它代入
(
X
0
X
0
X
0
X
0
X
)
\left( \begin{array}{l} X & 0 & X\\ 0 & X & 0\\ X & 0 & X \end{array} \right)
⎝⎛X0X0X0X0X⎠⎞
这样就好做了.
首先把询问转化成两个前缀和相减的形式,然后由对称性强制x>y,那么问题转化为求助阵中从
(
0
,
x
)
(0,x)
(0,x)开始连续对角线
r
r
r个的前缀和.
考虑最简单也是最基本的形式,最后一个点的横纵坐标的最大值为
3
3
3的幂次.
那么这个点一定在一个形如
(
X
0
X
0
X
0
X
0
X
)
\left( \begin{array}{l} X & 0 & X\\ 0 & X & 0\\ X & 0 & X \end{array} \right)
⎝⎛X0X0X0X0X⎠⎞的矩阵中
讨论一下
(
0
,
x
)
(0,x)
(0,x)可以在三个位置,分别递归去算就行了.
这样,我们解决了最基本的问题.
考虑如何推广
对于任意的
(
0
,
x
)
(0,x)
(0,x)最后一个点的横纵坐标最大值不一定落在
X
X
X的边界.
很自然地可以想到构造
x
=
∑
i
3
i
p
i
x=\sum_i3^ip_i
x=i∑3ipi然后继续讨论
(
0
,
x
)
(0,x)
(0,x)去做即可.
需要注意一些细节.
Code(考场)
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
LL x, Q, y, d, p[50];
inline LL read() {
LL res = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
return res;
}
LL g(int x, LL y) {
if(y & 1) return 0;
if(x == 0 && y == 0) return 1;
LL tmp = p[x - 1] << 1;
if(y < p[x - 1]) return 3 * g(x - 1, y);
else if(y < tmp) return g(x - 1, tmp - y);
else return g(x - 1, y - tmp);
}
LL f(LL x, LL r) {
if(r <= 0) return 0;
LL res = 0, s;
for(int i = 39; i >= 0; --i) {
s = x + r;
if(s >= p[i]) {
if(s / p[i] == 1) {
if(x >= p[i]) break;
res += g(i, x);
r -= p[i], ++i;
}
else if(s / p[i] == 2) {
LL tmp = p[i] << 1;
if(x < p[i])
res += (g(i, x) << 1),
r -= tmp, ++i;
else if(x >= p[i] && x < tmp)
x = tmp - x,
r = min(p[i] - x, r - x), ++i;
else if (x >= tmp)
x -= tmp, ++i;
}
if(r <= 0) break;
}
}
return res;
}
int main() {
Q = read();
p[0] = 1;
for(int i = 1; i <= 39; ++i)
p[i] = p[i - 1] * 3;
while(Q--) {
d = read(), x = read(), y = read();
if(y > x) swap(x, y);
printf("%lld\n",f(x - y, d + y + 1) - f(x - y, y));
}
}