[BZOJ]4513 [SDOI2016]储能表 (数位dp)
题意
计算
\[\sum_{i=0}^{n - 1}\sum_{j = 0}^{m - 1}max((i\ xor\ j) - k,\ 0)
\]
题解
首先需要把题意抽象出来。
注意到\(i\ xor\ j \le k\)时,这个式子就直接等于0,所以只要求\(i\ xor\ j > k\)的这部分值就行了。
去掉max之后拆开求和符号,就是
\[\sum_{i=0}^{n - 1}\sum_{j = 0}^{m - 1}(i\ xor\ j) * [i\ xor\ j > k] - \sum_{i=0}^{n - 1}\sum_{j = 0}^{m - 1} k* [i\ xor\ j > k]
\]
分别求出这两个东西就行了,就是求\(i\ xor\ j > k\)的ij对数和异或的和。
用数位dp来解决。
套上数位dp标准板子。
\(dfs(i, limita, limitb, limitk)\)表示现在是第i位,a,b,k有没有收到上限限制。
转移的时候对数可以直接加上,异或和为前面的异或和+当前这一位取值情况*前面的对数。
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define mk make_pair
#define Mid ((l + r) >> 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read(){
char c; int num, f = 1;
while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
return f * num;
}
int n, m, k, mod, vis[70][2][2][2];
pii f[70][2][2][2];
void up(int &a, int b) {a = a + b; if(a >= mod) a -= mod;}
pii dfs(int q, int limita, int limitb, int limitc) {
if(q == -1) return mk(1, 0);
if(vis[q][limita][limitb][limitc]) return f[q][limita][limitb][limitc];
vis[q][limita][limitb][limitc] = 1;
int la, lb, lk, ans = 0;
la = limita ? ((n >> q) & 1) : 1;
lb = limitb ? ((m >> q) & 1) : 1;
lk = limitc ? ((k >> q) & 1) : 0;
for(int i = 0; i <= la; i++) {
for(int j = 0; j <= lb; j++) {
if(limitc && (i ^ j) < lk) continue;
pii nw = dfs(q - 1, limita && (i == la), limitb && (j == lb), limitc && ((i ^ j) == lk));
up(f[q][limita][limitb][limitc].first, nw.first);
up(f[q][limita][limitb][limitc].second, ((1ll << q) * (i ^ j) % mod * nw.first % mod + nw.second) % mod);
}
}
return f[q][limita][limitb][limitc];
}
void work() {
memset(f, 0, sizeof(f));
memset(vis, 0, sizeof(vis));
n = read() - 1; m = read() - 1;
k = read(); mod = read();
pii ans = dfs(61, 1, 1, 1);
printf("%lld\n", ((ans.second - k % mod * ans.first) % mod + mod) % mod );
}
signed main()
{
int Case = read();
while(Case--) work();
return 0;
}