GYM102978A Ascending Matrix 题解

LGV引理的题目。

我们考虑这道题目是从\((1,1)\)\((n,m)\),然后选取不交叉的\(k-1\)条线插在中间,每一条划分出一个数值的范围,题目限制相当于\((r,c)\)坐下方要有\(v-1\)条线。

我们考虑把线实际化成为一个点,不交叉变为点不相交,可以使用LGV引理。\((r,c)\)位移到了\((r+v-1,c+v-1)\),确保一下这一个点不会被选。

对于\(v-1\)条的限制,我们可以给\((r+v-1,c+v-1)\)左下方的若干条线段的权值从\(1\)改为\(x\),直接计算肯定是会爆炸的,但是根据拉格朗日插值的写法,我们可以给\(x\)带入\(k\)个值,运用LGV引理,就可以求出来方案数了。

2025.4.30补充:注意,带入\(x\)是往左下角,而不是下方,因为没来一条线都会位移。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int modd=998244353;
int a[310][310],K,n,m,jie[1010],ni[1010],zhi,x[1010],y[1010],r,c,v;
int g[1010],lin[1010],f[1010],jvch[310][310],jvxi[310][310],t[1010];
int kuai(int q,int w){
	zhi=1;
	while(w){
		if(w&1){
			zhi=zhi*q%modd;
		}
		q=q*q%modd;
		w=w>>1;
	}
	return zhi;
}
inline int Guass(){
	int ans=1;
	for(int i=1;i<=K;i++){
		if(!a[i][i]){
			for(int j=i+1;j<=K;j++){
				if(a[j][i]){
					swap(a[i],a[j]);
					ans=modd-ans;
					break;
				}
			}
		}
		ans=ans*a[i][i]%modd;
		int inv=kuai(a[i][i],modd-2);
		for(int j=i+1;j<=K;j++){
			int tmp=a[j][i]*inv%modd;
			for(int k=i;k<=K;k++){
				a[j][k]=(a[j][k]-tmp*a[i][k]%modd+modd)%modd;
			}
		}
	}
	return ans;
}
int C(int q,int w){
	return jie[q]*ni[w]%modd*ni[q-w]%modd;
}
int calc(int sx,int sy,int ex,int ey){
	if(ex>sx||ey<sy){
		return 0;
	}
	return C(sx-ex+ey-sy,ey-sy);
}
void solve(){
	for(int i=1;i<=K+1;i++){
		t[i]=1;
		for(int j=1;j<=K+1;j++){
			if(i!=j){
				t[i]=t[i]*(x[i]-x[j])%modd;
			}
		}
		t[i]=(t[i]+modd)%modd;
		t[i]=y[i]*kuai(t[i],modd-2)%modd;
	}
	lin[0]=1;
	for(int i=1;i<=K+1;i++){
		for(int j=K;j>0;j--){
			lin[j]=(lin[j-1]+lin[j]*(modd-x[i])%modd)%modd;
		}
		lin[0]=lin[0]*(modd-x[i])%modd;
	}
	for(int i=1;i<=K+1;i++){
		int inv=kuai(modd-x[i],modd-2);
		g[0]=lin[0]*inv%modd;
		for(int j=1;j<=K;j++){
			g[j]=(lin[j]-g[j-1]+modd)*inv%modd;
		}
		for(int j=0;j<=K;j++){
			f[j]=(f[j]+t[i]*g[j]%modd+modd)%modd;
		}
	}
	return;
}
signed main(){
	jie[0]=1,ni[0]=1;
	for(int i=1;i<=1000;i++){
		jie[i]=jie[i-1]*i%modd;
		ni[i]=kuai(jie[i],modd-2);
	}
	cin>>n>>m>>K>>r>>c>>v;
	r+=v-2;
	c+=v-2;
	K--;
	for(int i=0;i<K;i++){
		for(int j=0;j<K;j++){
			jvch[i][j]=(calc(n+i,i,j,m+j)-calc(n+i,i,r,c)*calc(r,c,j,m+j)%modd+modd)%modd;
			for(int d=1;d<=r&&d<=c;d++){
				int xx=r-d,yy=c-d;
				int res=calc(n+i,i,xx,yy)*calc(xx,yy,j,m+j)%modd;
				jvxi[i][j]=(jvxi[i][j]+res)%modd;
				jvch[i][j]=(jvch[i][j]-res+modd)%modd;
			}
		}
	}
	for(int i=1;i<=K+1;i++){
		memset(a,0,sizeof(a));
		x[i]=i;
		for(int j=0;j<K;j++){
			for(int k=0;k<K;k++){
				a[j+1][k+1]=(jvch[j][k]+jvxi[j][k]*i)%modd;
			}
		}
		y[i]=Guass();
	}
	solve();
	cout<<f[v-1];
	return 0;
}
posted @ 2025-04-29 19:59  特别之处  阅读(18)  评论(0)    收藏  举报