题解:P10890 【烂题杯 Round 1】可持久化糖果树

· · 题解

很牛的题!拜谢出题人。

个人感觉 3^m 的做法更加自然,因为这是直接单位根反演的结果。

Solution

考虑单位根反演:

[k|n]=\frac 1k\sum_{i=0}^{k-1}\omega_k^{in}

我们应用它来刻画 \sum_{x=1}^ka_{i,j,x}\equiv 0\pmod 3。一个节点 i 是合法的当且仅当:

\frac 1{3^m}\prod_{j=1}^m(1+\omega_3^{\sum a_{i,j,x}}+\omega_3^{2\sum a_{i,j,x}})=1

则答案即为

\frac 1{3^m}\sum_{i=1}^n\sum_{j=1}^m(1+\omega_3^{\sum a_{i,j,x}}+\omega_3^{2\sum a_{i,j,x}})

将式子展开,得到

&\frac 1{3^m}\sum_{i=1}^n\sum_b\omega_3^{\sum_{j=1}^mb_j\sum_{x=1}^k a_{i,j,x}}\\ =&\frac 1{3^m}\sum_{i=1}^n\sum_{b}\omega_3^{\sum_{x=1}^k\sum_{j=1}^ma_{i,j,x}b_j} \end{aligned}

其中序列 b 满足 |b|=m,b_i\in\{0,1,2\}

现在我们已经可以做到 n3^mk 或更快的单次询问了,考虑支持修改。设 a_{i,j,x}\gets a_{i,j,x}\times d_x,继续推式子:

&\frac 1{3^m}\sum_{i=1}^n\sum_{b}\omega_3^{\sum_{x=1}^k \sum_{j=1}^md_xa_{i,j,x}b_j}\\ =&\frac 1{3^m}\sum_{i=1}^n\sum_{b}\omega_3^{\sum_{x=1}^kd_x\sum_{j=1}^ma_{i,j,x}b_j} \end{aligned}

对于确定的 a_ib,我们可以得到序列 c,满足 c_x=\sum_{j=1}^ma_{i,j,x}b_j。记录 cnt_c 表示上述 c 的出现次数,答案即为:

\frac 1{3^m}\sum_ccnt_c\prod_{x=1}^k\omega_3^{c_xd_x} 总的复杂度即为 $O(n3^mmk+k3^k+qk)$。 Bonus:其实上述的 $k3^k$ DP 即为 3-FWT。 ### Code 朴素的实现需要扩域。但我们可以选一个大于等于 $n$ 的质数 $p$ 满足 $3|(p-1)$,这样在 $\mathbb F_p$ 中就存在 $\omega_3$,算答案时直接对 $p$ 取模即可。 ```cpp #include<bits/stdc++.h> using namespace std; using ui=unsigned int; using ll=long long; using ull=unsigned long long; using i128=__int128; using u128=__uint128_t; using pii=pair<int,int>; #define fi first #define se second constexpr int N=1e6+5,M=5,K=13,mod=1145140831,w1=431040359,w2=714100471; int n,m,k,X,q,a[M][K],b[K],p3[K],num[N],tmp[K]; ll F[N]; inline ll qpow(ll a,ll b){ ll res=1; for(;b;b>>=1,a=a*a%mod) if(b&1)res=res*a%mod; return res; } void dfs(int x){ if(x==m+1){ int cur=0,sum; for(int i=1;i<=k;i++){ sum=0; for(int j=1;j<=m;j++) sum+=b[j]*a[j][i]; cur+=p3[i-1]*(sum%3); } ++F[cur]; return; } for(int i=0;i<3;i++){ b[x]=i; dfs(x+1); } } void FWT(ll *F,int n){ for(int i=1;i<n;i*=3) for(int j=0;j<n;j+=i*3) for(int k=0;k<i;k++){ ll x=F[j+k],y=F[i+j+k],z=F[(i<<1)+j+k]; F[j+k]=(x+y+z)%mod; F[i+j+k]=(x+w1*y+w2*z)%mod; F[(i<<1)+j+k]=(x+w2*y+w1*z)%mod; } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m>>k>>X; p3[0]=1; for(int i=1;i<=k;i++)p3[i]=p3[i-1]*3; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) for(int x=1;x<=k;x++) a[j][x]=(X*(i+1ll)+(X^(j*x)))%1000000000%3; dfs(1); } FWT(F,p3[k]); ll inv=qpow(3,mod-m-1); for(int i=0;i<p3[k];i++)F[i]=F[i]*inv%mod; for(int i=1;i<=k;i++)num[0]+=p3[i-1]; int ans=F[num[0]]; cin>>q; for(int i=1;i<=q;i++){ int x=(X^i)%i,y=(X^i)%k+1,z=(X+(X^i))%999999999%3; for(int j=1;j<=k;j++)tmp[j]=num[x]/p3[j-1]%3; tmp[y]=(tmp[y]*z)%3; for(int j=1;j<=k;j++)num[i]+=tmp[j]*p3[j-1]; ans^=F[num[i]]; } cout<<ans<<'\n'; return 0; } ```