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)\) 这个单位矩阵的贡献次数(不是期望)就是:

\[\sum\limits_{l=1,l\text{为奇数}}^{k}\dbinom{k}{l}\times \left [i\times(m-i)\times j\times (m-j)\right ]^l\times[\dbinom{m}{2}^2-i\times(m-i)\times j\times (m-j)]^{k-l} \]

\(\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\) 是因为快速幂。)

posted @ 2021-09-17 16:14  Rolling_Code  阅读(106)  评论(0)    收藏  举报