Codeforces 772D - Varying Kibibits(高维差分+二项式定理维护 k 次方和)
首先很容易注意到一件事,那就是对于所有 \(f(S)\) 可能成为 \(x\) 的集合 \(S\),必定有 \(\forall y\in S\),\(x\) 的每一位都 \(\le y\) 的对应位,于是我们考虑设 \(h(x)\) 表示所有满足 \(x\) 的对应位都小于 \(f(S)\) 的对应位的 \(S\) 的贡献之和,显然我们求出 \(h(x)\) 之后,可以把 \(0\sim 999999\) 中的数都看作一个拥有六个维度,每个维度中的数都 \(\in[0,9]\) 的元素,然后仿照二进制下的高维差分跑一遍高维差分即可。
接下来考虑怎样求出 \(h(x)\),下记 \([x\subseteq y]\) 表示 \(x\) 是否每一位都 \(\le y\) 的对应位,那显然根据之前的定义有 \(h(x)=\sum\limits_{S\subseteq T}[\forall y\in S,x\subseteq y](\sum\limits_{y\in S}y)^2\),这里面带个平方,可能不是特别显然,我们考虑一个简单些的问题,那就是假设每个集合 \(S\) 的贡献都是 \(1\) 而不是 \((\sum\limits_{y\in S}y)^2\),那我们只需求出 \(c(x)=\sum\limits_{y\in T}[x\subseteq y]\),那么显然就有 \(h(x)=2^{c(x)}\)。回到原题,注意到我们高维前缀和的实质是合并两个集合 \(S,T\) 的贡献,也就是倘若我们已经知道了 \(S\) 的贡献和 \(T\) 的贡献,怎样支持快速求出 \(S\cup T\) 的贡献。我们如果记 \(st(x)=\{y|y\in T,x\subseteq y\}\),那么 \(h(x)=\sum\limits_{S\subset st(x)}(\sum\limits_{y\in S}y)^2\)。并且此题还带个平方,做过 P6144 [USACO20FEB]Help Yourself P 的同学应该都知道,碰到这类高次方求和的问题,我们都可用二项式定理将其拆成若干个低次方的和,然后将它们一一合并即可。具体来说,根据二项式定理初一课内有 \((x+y)^2=x^2+2xy+y^2\),故我们对于每个集合 \(S\) 维护零次方和、一次方和和二次方和,即 \(S_0=\sum\limits_{S'\subseteq S}1,S_1=\sum\limits_{S'\subseteq S}\sum\limits_{x\in S'}x,S_2=\sum\limits_{S'\subseteq S}(\sum\limits_{x\in S'}x)^2\),那么当合并两个集合 \(S,T\) 时,就有:
- \((S\cup T)_0=\sum\limits_{U\subseteq(S\cup T)}1=\sum\limits_{U\subseteq S,V\subseteq T}1=\sum\limits_{U\subseteq S}\sum\limits_{V\subseteq T}1=S_0T_0\)
-
\[\begin{aligned}(S\cup T)_1&=\sum\limits_{U\subseteq(S\cup T)}\sum\limits_{x\in U}x=\sum\limits_{U\subseteq S,V\subseteq T}(\sum\limits_{x\in U}x+\sum\limits_{x\in V}x)\\&=\sum\limits_{U\subseteq S}\sum\limits_{V\subseteq T}(\sum\limits_{x\in U}x+\sum\limits_{x\in V}x)\\&=\sum\limits_{U\subseteq S}\sum\limits_{x\in U}x·\sum\limits_{V\subseteq T}1+\sum\limits_{V\subseteq T}\sum\limits_{x\in V}x·\sum\limits_{U\subseteq S}1\\&=S_1T_0+S_0T_0\end{aligned} \]
-
\[\begin{aligned}(S\cup T)_2&=\sum\limits_{U\subseteq(S\cup T)}(\sum\limits_{x\in U}x)^2=\sum\limits_{U\subseteq S,V\subseteq T}(\sum\limits_{x\in U}x+\sum\limits_{x\in V}x)^2\\&=\sum\limits_{U\subseteq S}\sum\limits_{V\subseteq T}((\sum\limits_{x\in U}x)^2+(\sum\limits_{x\in V}x)^2+2\sum\limits_{x\in U}x\sum\limits_{x\in V}x)\\&=\sum\limits_{U\subseteq S}(\sum\limits_{x\in U}x)^2·\sum\limits_{V\subseteq T}1+\sum\limits_{V\subseteq T}(\sum\limits_{x\in V}x)^2·\sum\limits_{U\subseteq S}1+2\sum\limits_{U\subseteq S}\sum\limits_{x\in U}x·\sum\limits_{V\subseteq T}\sum\limits_{x\in V}x\\&=S_2T_0+S_0T_2+2S_1T_1\end{aligned} \]
高维前缀和维护下即可,最好开个结构体,时间复杂度 \(6\times 999999\)。
老缝合怪了
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e6;
const int MOD=1e9+7;
int n,pw[MAXN+5],ret[MAXN+5];
struct data{
int sum0,sum1,sum2;
data(){sum0=sum1=sum2=0;}
data(int x){sum0=1;sum1=x;sum2=1ll*x*x%MOD;}
data(int _sum0,int _sum1,int _sum2):sum0(_sum0),sum1(_sum1),sum2(_sum2){}
data operator +(const data &rhs){
return data(
sum0+rhs.sum0,
(1ll*sum1*pw[rhs.sum0]+1ll*pw[sum0]*rhs.sum1)%MOD,
(1ll*sum2*pw[rhs.sum0]%MOD+2ll*sum1*rhs.sum1+1ll*pw[sum0]*rhs.sum2)%MOD);
}
} f[MAXN+5];
int main(){
scanf("%d",&n);pw[0]=1;
for(int i=1;i<=n;i++) pw[i]=2ll*pw[i-1]%MOD;
for(int i=1,x;i<=n;i++) scanf("%d",&x),f[x]=f[x]+data(x);
int cur=1;
for(int i=0;i<=5;i++){
for(int j=MAXN-1;~j;j--){
if((j/cur)%10!=9) f[j]=f[j]+f[j+cur];
}
cur=cur*10;
}
for(int i=0;i<MAXN;i++) ret[i]=f[i].sum2;
cur=1;
for(int i=0;i<=5;i++){
for(int j=0;j<MAXN;j++){
if((j/cur)%10!=9) ret[j]=(ret[j]-ret[j+cur]+MOD)%MOD;
}
cur=cur*10;
} ll ans=0;
for(int j=0;j<MAXN;j++) ans^=1ll*j*ret[j];
printf("%lld\n",ans);
return 0;
}