题意:
问题描述
Alice和JSL正在玩一个游戏(Bob呢?)。 Alice从 [l1,r1] 中选出一个数字 x ,JSL看到这个数字之后从 [l2,r2] 中取出一个数字 y ( y 可能和 x 相同)。最后他们计算出数字 z=x⊕y ( ⊕ 为异或运算)。Alice希望 z 尽可能大,而JSL希望 z 尽可能小。Alice和JSL都很聪明,那么 z 最后会是多少?
输入描述
第一行一个数 T ,表示数据组数。 对于每组数据有四个数 l1,r1,l2,r2 。 1≤T≤10000,0≤l1≤r1≤109,0≤l2≤r2≤109
输出描述
每组数据输出一行Case # x : ans 。 x 表示组数编号,从 1 开始。 ans 为 z 的值。
输入样例
2 1 4 3 8 1 3 4 7
输出样例
Case #1: 2 Case #2: 4题解:
1.把数想成二进制形式,从最高位开始依次枚举,对于每一位,Alice的策略是尽量让数字(0,1)和Jsl不一样,而jsl
的策略是尽量使数字和Alice一样
2.dfs + 剪枝
3.比较重要的两个剪枝就是当Jsl可用数的范围大于了Alice,那么直接返回,不需要再搜索了
4.每次递归,都尽可能的缩小上界r。
总结:
1.这个题目没有自己做出来,第二个剪枝没有想出来,而且数位dp法也是不会,以后再补上这个题吧
2.记得当时第一次用贪心写的,思路是错的,以后如果一个题是躺在床上或吃着饭想出来的话就先在草稿纸上演算一
遍再敲代码比较稳妥
3.草稿纸也一定要干净利索!
4.把大任务分成小任务,说白了就是制定很多的小目标,加快想题速度!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
int _,ans;
int state(int i,int l,int r)
{
if((1 << i) <= l)return 1;
else if((1 << i) > r)return 0;
else return -1;
}
void deal(int & l,int & r,int v,int i)
{
l = max(l - v,0);
r = min(max(r - v,0),(1 << i) - 1);
}
void dfs(int l1,int r1,int l2,int r2,int i,int cur)
{
if(l2 <= l1 && r1 <= r2 || i == -1)return;
if(cur + ((LL)1 << (i + 1)) - 1 < ans)return;
int st1 = state(i,l1,r1),st2 = state(i,l2,r2);
if(st1 >= 0 && st2 >= 0)
{
cur |= ((st1 ^ st2) << i);
ans = max(cur,ans);
deal(l1,r1,st1 << i,i) , deal(l2,r2,st2 << i,i);
dfs(l1,r1,l2,r2,i - 1,cur);
}
else if(st1 == -1 && st2 == -1)
{
dfs(l1,min(r1,(1 << i) - 1),l2,min(r2,(1 << i) - 1),i - 1,cur);
deal(l1,r1,1 << i,i) , deal(l2,r2,1 << i,i);
dfs(l1,r1,l2,r2,i - 1,cur);
}
else if(st1 >= 0 && st2 == -1)
{
deal(l1,r1,st1 << i,i) , deal(l2,r2,st1 << i,i);
dfs(l1,r1,l2,r2,i - 1,cur);
}
else// if(st1 == -1 && st2 >= 0)
{
cur |= (1 << i);
ans = max(cur,ans);
deal(l1,r1,!st2 << i,i) , deal(l2,r2,st2 << i,i);
dfs(l1,r1,l2,r2,i - 1,cur);
}
}
int main()
{
scanf("%d",&_);
for(int kcas = 1;kcas <= _;kcas++)
{
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
ans = 0;
dfs(l1,r1,l2,r2,30,0);
printf("Case #%d: %d\n",kcas,ans);
}
}