bzoj4513 储能表
求 $\sum\limits_{i=0}^{n-1} \sum\limits_{j=0}^{m-1} max((x \space xor \space j) - k,0)$ ,膜 $p$
$n,m \leq 10^{18},p \leq 10^9$,有 $5000$ 组数据
sol:
老年选手不会找规律,大力数位 dp
记
$F_{(i,n1,m1,k1)}$ 为考虑前 $i$ 位,是否卡 $n$ 的上界,是否卡 $m$ 的上界,是否卡 $k$ 的上界的所有 $(i,j)$ 异或和
$G_{(i,n1,m1,k1)}$ 为考虑前 $i$ 位,是否卡 $n$ 的上界,是否卡 $m$ 的上界,是否卡 $k$ 的上界的所有 $(i,j)$ 方案数
转移的时候讨论都不用讨论
#include<bits/stdc++.h> #define LL long long #define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i) #define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i) using namespace std; inline LL read() { LL x=0,f=1;char ch; for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f; for(;isdigit(ch);ch=getchar())x=10*x+ch-'0'; return x*f; } #define pii pair<LL, LL> #define FS first #define SC second int p,mxlen; int vis[70][2][2][2]; pii f[70][2][2][2]; LL n,m,k; void cal(LL n) { LL tmp = n; int cnt = 0; while(tmp) tmp>>=1,cnt++; mxlen = max(mxlen,cnt); } void inc(LL &x, LL y) { x += y; if (x >= p) x -= p; } pii dfs(int len,int n1,int m1,int k1){ if (len>mxlen) return make_pair(1,0); if (vis[len][n1][m1][k1]) return f[len][n1][m1][k1]; vis[len][n1][m1][k1] = 1; int nn=(n>>(mxlen-len))&1,mm=(m>>(mxlen-len))&1,kk=(k>>(mxlen-len))&1; for (int i=0;i<=(n1?nn:1);i++) for (int j=0;j<=(m1?mm:1);j++){ if (k1 && (i^j)<kk) continue; pii tmp=dfs(len+1,n1&&(i==nn),m1&&(j==mm),k1&&((i^j)==kk)); inc(f[len][n1][m1][k1].FS,tmp.FS); inc(f[len][n1][m1][k1].SC,((1ll<<(mxlen-len))*(i^j)%p*tmp.FS%p+tmp.SC)%p); } return f[len][n1][m1][k1]; } LL solve(LL n, LL m, LL k) { memset(f, 0, sizeof(f)); memset(vis, 0, sizeof(vis)); mxlen = 0; cal(n); cal(m); cal(k); pii ans = dfs(1, 1, 1, 1); return ((ans.SC % p - k % p * ans.FS % p + p) % p); } int main(){ int T = read(); while (T--) { n = read() - 1, m = read() - 1, k = read(), p = read(); printf("%lld\n", solve(n, m, k)); } }