GTW likes czf
Accepts: 6
Submissions: 29
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
从前,有两个人名叫GTW,DSY。一天,他们为了争夺DSY的妹子CZF,决定进行一次决斗。首先,CZF会给出一个区间l,l+1,l+2......r,和两个数G,T。现在,CZF会在G,T两个数中随机一个数X,在区间l,r中随机一个数Y,进行一种特殊的运算@。CZF想要快速知道有多少数字可能会是答案。 然而GTW并不会做这道题,但是为了赢得CZF,他就来寻求你的帮助。 由于答案可能会很大,所以把最终的答案模1000000007。 我们规定运算X @ Y =((X and Y) or Y) xor X.
输入描述
第1行 一个整数Test,表示有Test组数据。(Test≤10000) 第2行到第Test+1行,每行4个整数,l,r,G,T (1≤l,r,G,T≤1018,l≤r)
输出描述
共Test行,每行一个数字,表示答案。
输入样例
1 2 4 2 4
输出样例
4
Hint
2 xor 2=0,2 xor 3=1,2 xor 4=6 4 xor 2=6,4 xor 3=7,4 xor 4=0 总共有4个数字是 0 1 6 7
官方题解:首先会发现x @ y=x xor y,(ps:出题人很良心,在样例解释里暴露了这一事实) 并且一个数字和其它若干个不同的数字xor的结果肯定是互不相同的,所以最后的答案就是(r−l+1)∗2−重复数字。
那么如何求重复数字呢。显然需要满足g xor x=t xor y,x和y是我们从区间[l,r]中挑出来的数字,通过移项,就变成了g xor t=x xor y,所以我们要求[l,r]中有多少对x,y异或等于g xor t这个东西显然可以数位dp。
所以这个题目就是要求从0到m里面 与从0到n里面有多少对元素的 异或 等于给定的值。
用dp[i][x][y]表示进行到第i位合法的数量,x=1时表示a还是原数,即最大值不变。y=1时表示b仍是原数,即最大值不变,剩下的就是不断“释放”的一个过程。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
ll x;
ll le, ri, G, T;
int nn[65], mm[65], xx[65];
ll dp[65][2][2];
void input()
{
scanf("%lld%lld%lld%lld", &le, &ri, &G, &T);
}
ll cal(ll n, ll m)
{
memset(dp, 0, sizeof(dp));
int i;
for (i = 63; i >= 0; i--)
{
nn[i] = (n >> i) & 1;
mm[i] = (m >> i) & 1;
xx[i] = (x >> i) & 1;
}
int flag = 0;//找首位的标记
for (i = 62; i >= 0; i--)
{
if (flag == 0)
{
if (!nn[i] && !mm[i] && !xx[i])//0 0 0
continue;
else if (!nn[i] && !mm[i] && xx[i])//0 0 1
return 0;
else if (!nn[i] && mm[i] && !xx[i])//0 1 0
{
//因为是首位,只能是0 0 0,不可能是1 1 0
dp[i][1][0] = 1;
}
else if (!nn[i] && mm[i] && xx[i])//0 1 1
{
//因为是首位,只能是0 1 1,不可能是1 0 1
dp[i][1][1] = 1;
}
else if (nn[i] && !mm[i] && !xx[i])//1 0 0
{
//因为是首位,只能是0 0 0,不可能是1 1 1
dp[i][0][1] = 1;
}
else if (nn[i] && !mm[i] && xx[i])//1 0 1
{
//因为是首位,只能是1 0 1,不可能是0 1 1
dp[i][1][1] = 1;
}
else if (nn[i] && mm[i] && !xx[i])//1 1 0
{
//这时可以是 1 1 0,也可以是0 0 0
dp[i][1][1] = 1;
dp[i][0][0] = 1;
}
else if (nn[i] && mm[i] && xx[i])//1 1 1
{
//这时可以是 1 0 1,也可以是0 1 1
dp[i][1][0] = 1;
dp[i][0][1] = 1;
}
flag = 1;
}
else
{
if (!nn[i] && !mm[i] && !xx[i])//0 0 0
{
dp[i][1][1] = dp[i + 1][1][1];
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
}
else if (!nn[i] && !mm[i] && xx[i])//0 0 1
{
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
}
else if (!nn[i] && mm[i] && !xx[i])//0 1 0
{
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
//1 1 0的情况
dp[i][0][0] += dp[i + 1][0][1];
//0 0 0的情况
dp[i][1][0] += dp[i + 1][1][1];
}
else if (!nn[i] && mm[i] && xx[i])//0 1 1
{
dp[i][1][1] = dp[i + 1][1][1];
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
// 1 0 1
dp[i][0][0] += dp[i + 1][0][1];
}
else if (nn[i] && !mm[i] && !xx[i])//1 0 0
{
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
//0 0 0的情况把n这部分释放了出来
dp[i][0][0] += dp[i + 1][1][0];
dp[i][0][1] += dp[i + 1][1][1];
}
else if (nn[i] && !mm[i] && xx[i])//1 0 1
{
dp[i][1][1] = dp[i + 1][1][1];
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
// 0 1 1
dp[i][0][0] += dp[i + 1][1][0];
}
else if (nn[i] && mm[i] && !xx[i])//1 1 0
{
dp[i][1][1] = dp[i + 1][1][1];
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
//0 0 0
dp[i][0][0] += (dp[i + 1][1][0] + dp[i + 1][0][1] + dp[i + 1][1][1]);
}
else if (nn[i] && mm[i] && xx[i])//1 1 1
{
dp[i][0][1] = dp[i + 1][0][1];
dp[i][1][0] = dp[i + 1][1][0];
dp[i][0][0] = dp[i + 1][0][0] * 2;
//0 1 1
dp[i][0][1] += dp[i + 1][1][1];
dp[i][0][0] += dp[i + 1][1][0];
//1 0 1
dp[i][1][0] += dp[i + 1][1][1];
dp[i][0][0] += dp[i + 1][0][1];
}
}
}
return (dp[0][0][0] + dp[0][1][0] + dp[0][0][1] + dp[0][1][1])%mod;
}
void solve()
{
x = G^T;
ll ans = ((ri - le + 1) * 2) % mod;
ans = (ans - (cal(ri, ri) - cal(le - 1, ri) * 2 + cal(le-1, le-1)) % mod + mod) % mod;
printf("%lld\n", ans);
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
int t;
scanf("%d", &t);
while (t--)
{
input();
solve();
}
//system("pause");
return 0;
}