题意: Alice和JSL正在玩一个游戏(Bob呢?)。 Alice从[l1,r1][{l}_{1},{r}_{1}][l1,r1]中选出一个数字xxx,JSL看到这个数字之后从[l2,r2][{l}_{2},{r}_{2}][l2,r2]中取出一个数字yyy(yyy可能和xxx相同)。 最后他们计算出数字z=x⊕yz=x\oplus yz=x⊕y(⊕\oplus⊕为异或运算)。Alice希望zzz尽可能大,而JSL希望zzz尽可能小。Alice和JSL 都很聪明,那么zzz最后会是多少?
第一行一个数TTT,表示数据组数。
对于每组数据有四个数l1,r1,l2,r2{l}_{1},{r}_{1},{l}_{2},{r}_{2}l1,r1,l2,r2。
1≤T≤10000,0≤l1≤r1≤109,0≤l2≤r2≤1091\leq T\leq 10000,0 \leq {l}_{1} \leq {r}_{1} \leq {10}^{9}, 0 \leq {l}_{2} \leq {r}_{2} \leq {10}^{9}1≤T≤10000,0≤l1≤r1≤109,0≤l2≤r2≤109
每组数据输出一行Case #xxx: ansansans。xxx表示组数编号,从111开始。ansansans为zzz的值。
2
1 4 3 8
1 3 4 7
Case #1: 2
Case #2: 4
思路:
有点博弈的味道。首先看清楚题目,是Alice先选数字,JSL后选,也就是说对于Alice的每一个选择,JSL为了使两个数的异或值最小,会有有一个唯一解。那么我们只要讨论Alice的选择,选出结果最大的就可以了。
因为要考虑异或,所以很自然的想到2进制。从高位到低位根据上下界限考虑当前位选0还是1.
第一种情况:其中一个人在当前位的选择只有一种。另外一个人肯定会选择对自己有利的一个,比如Alice在当前位只能选0,那么JSL为了使结果最小肯定会选0,这样这一位的结果就是0。这里是可以贪心不用考虑后面的,因为2进制后面位加起来都没有高位多。
第二种情况:两个人都只能选一个,那么这一位就是的结果也就是这两个值的异或。
第三种情况:两个人都有可以选择0或1。这种情况从当前位的结果而言,Alice肯定是占不到便宜的,无论Alice选什么,JSL肯定会选择和她一样的来使结果为0。但是Alice的选择会影响到后面的选择,所以这里要深搜来讨论Alice的选择选出结果比较大的一种选择。
最后这里有一个关键的地方,就拿第一个样例来说:
1 4 3 8
Alice的上界是4下界是1
JSL的上界是8下界是3
化成二进制
Alice
上界:0100
下界:0001
JSL
上界:1000
下界:0011
第一位Alice只能选0,那么JSL肯定会选0。
关键在JSL选0后会对后面的选择产生什么影响呢
后面位上界的限制将全部可以选1,因为第一位上界是1,这里选了0,那么后面就算都选1也不可能超过1000,最大就是0111。这里好好理解一下
我们假设这里JSL选了1,那么又会有什么变化呢
后面位下界的限制将全部可以选0,因为第一位下界是0,这里选了1,那么无论后面选多少0,比如1000也不可能比0011小,都是满足在范围内的。
所以我们设dp[pos][f1][f2][f3][f4],pos表示当前位,f1表示Alice的下界是否可以全选0了,f2表示Alice的上界是否可以都选1了,f3,f4,表示JSL的上下界(同Alice);
具体看代码了
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define LL long long int
using namespace std;
int T, L1, R1, L2, R2;
int dp[40][2][2][2][2];
int dfs(int pos,int f1,int f2,int f3,int f4)
{
if(pos < 0) return 0;
if(f1 == 0 && f2 == 0 && f3 == 0 && f4 == 0) return 0;
if(dp[pos][f1][f2][f3][f4] != -1) return dp[pos][f1][f2][f3][f4];
int x1 = f1 ? (L1 >> pos)&1 : 0;
int y1 = f2 ? (R1 >> pos)&1 : 1;
int x2 = f3 ? (L2 >> pos)&1 : 0;
int y2 = f4 ? (R2 >> pos)&1 : 1;
int ret = 0;
if(x1 == y1 && x2 == y2)
{
ret = dfs(pos - 1,f1,f2,f3,f4) + (x1^x2)*(1 << pos);
}
else if(x1 == y1 && x2 != y2)
{
ret = dfs(pos - 1,f1,f2,f3 && x1 == x2,f4 && y1 == y2);
}
else if(x1 != y1 && x2 == y2)
{
ret = dfs(pos - 1,f1 && x1 != x2,f2 && y1 != y2,f3,f4) + (1 << pos);
}
else if(x1 != y1 && x2 != y2)
{
ret = max(ret, dfs(pos - 1,f1,0,f3,0));
ret = max(ret, dfs(pos - 1,0,f2,0,f4));
}
return dp[pos][f1][f2][f3][f4] = ret;
}
int main()
{
scanf("%d", &T);
for(int Case = 1; Case <= T; ++Case)
{
memset(dp, -1, sizeof(dp));
scanf("%d%d%d%d",&L1,&R1,&L2,&R2);
printf("Case #%d: %d\n", Case, dfs(30,1,1,1,1));
}
return 0;
}