JZOJ 7237. 【USACO 2021 February Contest, Gold】Problem 3 Count the Cows
考虑 x , y x,y x,y 满足情况,当且仅当 x x x 和 y y y 的三进制表示位下每一位奇偶性相同。
所以题目转化为有多少个 z z z 满足 ( x + z , y + z ) (x+z,y+z) (x+z,y+z) 满足条件,注意 0 ≤ z ≤ d 0\leq z\leq d 0≤z≤d 。
考虑数位 dp ,设 f i , 0 / 1 , 0 / 1 , 0 / 1 f_{i,0/1,0/1,0/1} fi,0/1,0/1,0/1 分别表示构造到第 i i i 位的 z z z , 当前 x + z , y + z x+z,y+z x+z,y+z 分别是否进位,当前是否确定 z < d z<d z<d 的方案数。
考虑转移,在 dfs 上枚举当前位选择的数转移。设上一次存的进位分别为 c k 1 , c k 2 ck1,ck2 ck1,ck2 , 当前枚举进位 j , k j,k j,k ,那么我们要判断 x + z − 3 c k 1 + j x+z-3ck1+j x+z−3ck1+j 和 y + z − 3 c k 2 + k y+z-3ck2+k y+z−3ck2+k 是否合法。
#include<bits/stdc++.h>
using namespace std;
int q;
typedef long long ll;
ll a[50],b[50],c[50],f[50][2][2][2],g[50][2][2][2];
ll dfs(ll len,ll ck1,ll ck2,ll ck3){
if (len==0){
if (ck1==0&&ck2==0)return 1;
else return 0;
}
if (f[len][ck1][ck2][ck3]!=-1)return f[len][ck1][ck2][ck3];
ll lim=2,ans=0;
if (ck3==1){
lim=c[len];
}
for (ll i=0;i<=lim;i++){
for (ll j=0;j<=1;j++){
for (ll k=0;k<=1;k++){
ll x=a[len]+i-ck1*3+j;
ll y=b[len]+i-ck2*3+k;
if (x>=0&&y>=0&&x<=2&&y<=2&&x%2==y%2){
if (ck3==1&&i==c[len])ans+=dfs(len-1,j,k,1);
else ans+=dfs(len-1,j,k,0);
}
}
}
}
f[len][ck1][ck2][ck3]=ans;
return ans;
}
int main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&q);
while (q--){
memset(f,-1,sizeof(f));
memset(g,0,sizeof(g));
ll x,y,d;
scanf("%lld%lld%lld",&d,&x,&y);
ll len1=0,len2=0,len3=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
while (d){
c[++len3]=d%3;
d/=3;
}
while (x){
a[++len1]=x%3;
x/=3;
}
while (y){
b[++len2]=y%3;
y/=3;
}
len1=40;
len2=40;
len3=40;
printf("%lld\n",dfs(len3,0,0,1));
}
}