P7245 灯光效果 题解
1.题目大意
-
\(n\times n\) 的矩阵,初始全部为 \(0\),两个长为 \(m\) 的单调递增数列 \(x_i,y_i\);
-
每次等概率地随机选择 \(4\) 个整数 \(i_1,i_2,j_1,j_2\),满足 \(1\le i_1<i_2\le m,1\le j_1<j_2\le m\),并对 \((x_{i_1}+1,y_{j_1}+1)\) 和 \((x_{i_2},y_{j_2})\) 为左上和右下端点的矩阵进行染色,共进行 \(k\) 次操作;
-
求结束时矩阵内元素和的期望值 \(\bmod 998244353\);
-
\(2\le m\le 1000,1\le n\le 10^9,1\le k\le 10^6\)。
2.算法分析
2.1 基础分析
看到 \(n\le 10^9\),就意识到了事情不对。
复杂度几乎不太可能包含 \(n\)。
然后观察一下操作的形式,发现可以只考虑以 \((x_{i}+1,y_{j}+1)\) 和 \((x_{i+1},y_{j+1})\) 为左上和右下端点的矩阵(下称之为单位矩阵)!
为什么?因为每一个操作的矩阵都可以由若干个单位矩阵构成!
现在重新定义坐标,以 \((x_{i}+1,y_{j}+1)\) 和 \((x_{i+1},y_{j+1})\) 为左上和右下端点的矩阵缩小为一个格子 \((i,j)\)。
所以我们只需要对所有的单位矩阵做期望就可以了。
对于每一个单位矩阵 \((i,j)\),可以知道只有操作次数为奇数才会被计入期望的计算,需要 \(i_1\le i,i_2\ge i+1,j_1\le j,j_2\ge j+1\) 时才会被操作,所以对于一次操作,\((i,j)\) 被操作的选择总数为 \(i\times(m-i)\times j\times (m-j)\)。所以没有被操作到的选择总数为 \(\dbinom{m}{2}^2-i\times(m-i)\times j\times (m-j)\)。
所以 \((i,j)\) 这个单位矩阵的贡献次数(不是期望)就是:
\(\dbinom{k}{l}\):\(k\) 次操作中选择 \(l\) 次操作到这个单位矩阵;
\([i\times(m-i)\times j\times (m-j)]^l\):\(l\) 次影响的操作种数;
\([\dbinom{m}{2}^2-i\times(m-i)\times j\times (m-j)]^{k-l}\):剩余 \(k-l\) 次不影响的操作种数。
然后这份思路写出来实测 \(40pts\)。
时间复杂度 \(\mathcal{O}(m^2\times k\log k)\)。(有个 \(\log\) 是因为要用快速幂。)
2.2 优化
想办法把一个 \(k\) 的复杂度优化掉我们就做完了!
所以我们来用一种数学里比较常用的处理一大堆组合数的和的方法——构造多项式+二项式展开。
来看一个东西:
\((x+y)^n=\sum\limits_{l=0}^{n}\dbinom{n}{l}\times x^l\times y^{n-l}\);
\((y-x)^n=\sum\limits_{l=0}^{n}(-1)^{l}\times \dbinom{n}{l}\times x^l\times y^{n-l}\);
这时候我们把它们减一减:
\((x+y)^n-(y-x)^n=2\times\sum\limits_{l=1,l\text{为奇数}}^{n}\dbinom{n}{l}\times x^l\times y^{n-l}\)
取 \(x=i\times(m-i)\times j\times (m-j),y=\dbinom{m}{2}^2-i\times(m-i)\times j\times (m-j),n=k\)
代入,左右同时除以 \(2\) 以后就可以发现就是我们推导出来的式子!
所以原来 \(k\) 的复杂度可以直接用两个快速幂解决掉!
然后可以较为轻松地得出总共 \(k\) 次操作共有 \(\dbinom{m}{2}^{2\times k}\) 种操作。
然后取一些逆元就可以解决题目。
3.Code
#include<bits/stdc++.h>
#define N 1009
#define MOD 998244353
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
inline ll read() {
ll x=0,f=1;int c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
ll n,m,k,f[N*N]={1},invf[N*N],x[N],y[N],ans,tmp,tot;
ll ksm(ll x,ll pw){
ll ans=1;
for(;pw;pw>>=1,x*=x,x%=MOD)
if(pw&1) ans*=x,ans%=MOD;
return ans;
}
ll C(ll n,ll m){//组合数
if(n==m) return 1;
return f[m]*invf[n]%MOD*invf[m-n]%MOD;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=read(),m=read(),k=read();
for(int i=1;i<=k;i++) f[i]=f[i-1]*i%MOD;//阶乘
invf[k]=ksm(f[k],MOD-2);
for(int i=k-1;i>=1;i--) invf[i]=invf[i+1]*(i+1)%MOD;//阶乘的逆元
for(int i=1;i<=m;i++) x[i]=read();
for(int i=1;i<=m;i++) y[i]=read();
for(int i=1;i<m;i++){
for(int j=1;j<m;j++){
tot=0;
tmp=(x[i+1]-x[i])*(y[j+1]-y[j])%MOD;//一个单位矩阵里面含有的格子数量
//for(int l=1;l<=k;l+=2) tot+=C(l,k)*ksm(i*(m-i),l)%MOD*ksm(j*(m-j),l)%MOD*ksm((m*(m-1)/2%MOD*m*(m-1)/2%MOD-i*(m-i)*j%MOD*(m-j)%MOD+MOD)%MOD,k-l)%MOD,tot%=MOD;
tot=(ksm(m*(m-1)/2%MOD*m*(m-1)/2%MOD,k)-ksm(m*(m-1)/2%MOD*m*(m-1)/2%MOD-2*i*(m-i)%MOD*j%MOD*(m-j)%MOD,k))%MOD;
if(tot%2) tot=(tot+MOD)/2%MOD,tot=(tot+MOD)%MOD;
else tot=tot/2%MOD,tot=(tot+MOD)%MOD;
tot*=tmp,tot%=MOD;//别忘了还原成格子的数量
ans+=tot;ans%=MOD;
}
}
//printf("%lld\n",ans);
ans*=ksm(ksm(m*(m-1)/2,2*k),MOD-2);//有理数取模
printf("%lld",ans%MOD);
return 0;
}
复杂度 \(\mathcal{O}(m^2\log k)\)。(同样的,\(\log\) 是因为快速幂。)

浙公网安备 33010602011771号