Count the Cows G
题目链接:luogu P7415
题目大意
有一个矩阵。
如果 x,y 这两个数,对于每个 k,它们除 3^k 的余数的奇偶性都相同,那 x,y 这个位置是 1,否则就是 0。
然后要你统计 x,y 到 x+d,y+d 这条对角线上有多少个 1。
思路
首先我们观察这个是否有
1
1
1。
那它每次都是
3
k
3^k
3k,其实就是要看它三进制的每一位是否都奇偶性对应相同。
然后你就考虑数位 DP。
大概也是从高位向低位搞,然后也是看是否跑满,然后还要看一个就是是否进位(因为你是两个数都加一个数,就加了可能会某一位进位),然后 DP 一下即可。
代码
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
int q, dd[51], xx[51], yy[51];
ll d, x, y, ans, rem[51][2][2][2];
bool ck(int x, int y) {
if (x < 0 || x > 2) return 0;
if (y < 0 || y > 2) return 0;
return (x & 1) == (y & 1);
}
ll dfs(int x, int a, int b, bool lim) {//数位 DP(x 是当前位数,ab 是两个的进位,lim 是是否选满)
if (!x) return (!a && !b);
if (rem[x][a][b][lim] != -1) return rem[x][a][b][lim];
ll re = 0;
for (int i = 0; i <= (lim ? dd[x] : 2); i++) {
for (int aa = 0; aa <= 1; aa++)
for (int bb = 0; bb <= 1; bb++) {
if (ck(xx[x] - 3 * a + aa + i, yy[x] - 3 * b + bb + i))
re += dfs(x - 1, aa, bb, lim & (i == dd[x]));
}
}
return rem[x][a][b][lim] = re;
}
int main() {
scanf("%d", &q);
while (q--) {
scanf("%lld %lld %lld", &d, &x, &y);
memset(dd, 0, sizeof(dd));
memset(xx, 0, sizeof(xx));
memset(yy, 0, sizeof(yy));
while (d) {
dd[++dd[0]] = d % 3;
d /= 3;
}
while (x) {
xx[++xx[0]] = x % 3;
x /= 3;
}
while (y) {
yy[++yy[0]] = y % 3;
y /= 3;
}
memset(rem, -1, sizeof(rem));
printf("%lld\n", dfs(50, 0, 0, 1));
}
return 0;
}