[FOJ][2042][The Mad Mathematician][数位dp]

/*
题目:The Mad Mathematician
题目来源:FOJ 2042
题目难度:难
题目内容或思路:
数位dp + xor

已知A,B,C,D,E五个数(long long型)
求下面程序所得sum的值
for (int i = A; i <= B; ++i)
for (int j = C; j <= D; ++j)
if ((i ^ j) > E)
sum += i ^ j;

dp[i][j] 表示第i位,状态为j时的情况数
sum[i][j] 表示第i位,状态为j时的sum值
第二维的状态分别用3个bit表示
第一个数i位之前是否已经小于他
第二个数i位之前是否已经小于他
E的i位之前是否已经大于他
做题日期:2011.6.4
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <ctime>
#include <cstdlib>
#include <bitset>
#include <algorithm>
using namespace std;

typedef long long ll;
#define R "%I64d"
const int mod = 1000000007;
ll dp[64][8], sum[64][8];

ll gao(ll a, ll b, ll e) {
if (a < 0 || b < 0) return 0;
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
dp[63][0] = 1;
for (int i = 62; i >= 0; --i) {
ll z = 1LL << i;
for (int pre = 0; pre < 8; ++pre) {
ll cnt = dp[i + 1][pre];
ll val = sum[i + 1][pre];
if (cnt == 0) continue;
for (int st = 0; st < 4; ++st) {
int u = st & 1, v = st >> 1;
int cur = 0;

if (pre & 2) cur |= 2;
else if (u == 0 && (a & z)) cur |= 2;
else if (u && (a & z) == 0) continue;

if (pre & 4) cur |= 4;
else if (v == 0 && (b & z)) cur |= 4;
else if (v && (b & z) == 0) continue;

if (pre & 1) cur |= 1;
else if ((u ^ v) && (e & z) == 0) cur |= 1;
else if ((u ^ v) == 0 && (e & z)) continue;

dp[i][cur] = (dp[i][cur] + cnt) % mod;
if (u ^ v)
sum[i][cur] = (sum[i][cur] + val + z % mod * cnt) % mod;
else
sum[i][cur] = (sum[i][cur] + val) % mod;
}
}
}
ll ans = 0;
for (int i = 1; i < 8; i += 2)
ans = (ans + sum[0][i]) % mod;
return ans;
}

void solve() {
ll a, b, c, d, e;
scanf(R R R R R, &a, &b, &c, &d, &e);
ll ans = gao(b, d, e) - gao(b, c - 1, e)
- gao(a - 1, d, e) + gao(a - 1, c - 1, e);
ans = (ans % mod + mod) % mod;
printf(R "\n", ans);
}

int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
#endif
int cas;
scanf("%d", &cas);
for (int i = 1; i <= cas; ++i) {
printf("Case %d: ", i);
solve();
}
return 0;
}

你可能感兴趣的:(Math)