原题: https://ac.nowcoder.com/acm/contest/887/H
题意:
给出一个 A , B , C A,B,C A,B,C,求出有多少对 ( x , y ) , x ∈ [ 1 , A ] , y ∈ [ 1 , B ] (x,y),x\in [1,A],y\in [1,B] (x,y),x∈[1,A],y∈[1,B],满足 x & y > C x\&y>C x&y>C或者 x ⊕ y < C x\oplus y<C x⊕y<C
解析:
“或者”不太好处理,取反,变为求多少对 ( x , y ) (x,y) (x,y)满足 x & y ≤ C x\&y\leq C x&y≤C并且 x ⊕ y ≥ C x\oplus y\geq C x⊕y≥C,在这个基础上分析每一位。
考虑 ( x , y ) (x,y) (x,y)在这一位的取值,下面的表可以说明情况(譬如11在 ⊕ \oplus ⊕下变为0, 0 < 1 0<1 0<1,与 x ⊕ y ≥ C x\oplus y\geq C x⊕y≥C矛盾)
` | 1 | 0 |
---|---|---|
01 | 区分 & \& &,不区分 ⊕ \oplus ⊕ | 不区分 & \& &,区分 ⊕ \oplus ⊕ |
00 | 区分 & \& &,使 ⊕ \oplus ⊕矛盾 | 不区分 & \& &,不区分 ⊕ \oplus ⊕ |
11 | 不区分 & \& &,使 ⊕ \oplus ⊕矛盾 | 使 & \& &矛盾,不区分 ⊕ \oplus ⊕ |
注意,区分之后,之后的怎么样无所谓,但是第一个位置如果矛盾就错了,因为位越高,影响越大。
我们在记忆化搜索的过程中,维护是否已经区分 & \& &和 ⊕ \oplus ⊕,是否解除 A , B A,B A,B限制,是否有一位1(不能取0)。
运行时加 3 m s 3ms 3ms,复杂度 O ( 2 6 ∗ 32 ) O(2^6*32) O(26∗32)
代码:
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const LL inf=(1ll<<40)-1;
LL a,b,c;
LL dp[2][2][2][2][40][2][2];
LL dfs(bool h1,bool h2,bool up1,bool up2,int p,bool And,bool Xor){
if(p==-1){
return h1&&h2;
}
if(~dp[h1][h2][up1][up2][p][And][Xor])return dp[h1][h2][up1][up2][p][And][Xor];
dp[h1][h2][up1][up2][p][And][Xor]=0;
bool f=0;
if(c&(1ll<<p))f=1;
if(f){
rep(i,0,1){
rep(j,0,1){
if(!up1&&i&&!(a&(1ll<<p)))continue;
if(!up2&&j&&!(b&(1ll<<p)))continue;
if(!Xor&&i==j)continue;
bool X[6]={up1,up2,And,Xor,h1,h2};
if(!up1&&i==0&&(a&(1ll<<p)))X[0]=1;
if(!up2&&j==0&&(b&(1ll<<p)))X[1]=1;
if(i==j&&i==0)X[2]=1;
if(i!=j)X[2]=1;
if(i)X[4]=1;
if(j)X[5]=1;
dp[h1][h2][up1][up2][p][And][Xor]+=dfs(X[4],X[5],X[0],X[1],p-1,X[2],X[3]);
}
}
}
else{
rep(i,0,1){
rep(j,0,1){
if(!up1&&i&&!(a&(1ll<<p)))continue;
if(!up2&&j&&!(b&(1ll<<p)))continue;
if(!And&&i==j&&i==1)continue;
bool X[6]={up1,up2,And,Xor,h1,h2};
if(!up1&&i==0&&(a&(1ll<<p)))X[0]=1;
if(!up2&&j==0&&(b&(1ll<<p)))X[1]=1;
if(i!=j)X[3]=1;
if(i)X[4]=1;
if(j)X[5]=1;
dp[h1][h2][up1][up2][p][And][Xor]+=dfs(X[4],X[5],X[0],X[1],p-1,X[2],X[3]);
}
}
}
return dp[h1][h2][up1][up2][p][And][Xor];
}
int main(){
int t;scanf("%d",&t);
while(t--){
memset(dp,-1,sizeof dp);
scanf("%lld%lld%lld",&a,&b,&c);
LL ans=dfs(0,0,0,0,32,0,0);
printf("%lld\n",a*b-ans);
}
}