HDU5208 Where is Bob(数位DP,dfs)

来源:互联网 发布:mac版千牛多账号登陆 编辑:程序博客网 时间:2024/06/06 00:50
题意Alice和JSL正在玩一个游戏(Bob呢?)。Alice从[l1,r1][{l}_{1},{r}_{1}][l1,r1]中选出一个数字xxx,JSL看到这个数字之后从[l2,r2][{l}_{2},{r}_{2}][l2,r2]中取出一个数字yyyyyy可能和xxx相同)。最后他们计算出数字z=x⊕yz=x\oplus yz=xy⊕\oplus为异或运算)。Alice希望zzz尽可能大,而JSL希望zzz尽可能小。Alice和JSL都很聪明,那么zzz最后会是多少?

输入描述
第一行一个数TTT,表示数据组数。对于每组数据有四个数l1,r1,l2,r2{l}_{1},{r}_{1},{l}_{2},{r}_{2}l1,r1,l2,r21≤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}1T10000,0l1r1109,0l2r2109
输出描述
每组数据输出一行Case #xxx: ansansansxxx表示组数编号,从111开始。ansansanszzz的值。
输入样例
21 4 3 81 3 4 7
输出样例
Case #1: 2Case #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 intusing 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;}


原创粉丝点击