其他分享
首页 > 其他分享> > YbOJ-网格序列【拉格朗日插值】

YbOJ-网格序列【拉格朗日插值】

作者:互联网

正题


题目大意

有一个\(n\times m\)的网格,在上面填上\([1,k]\)的数字,定义两个长度为\(n\)的序列\(a_i,b_i\)分别表示每一行/每一列的最大值。

求有多少种不同的合法\(a,b\)对。

\(1\leq n,m\leq 10^6,1\leq k\leq 10^9\)


解题思路

不难发现合法的\(a,b\)对只需要满足它们的最大值相等。

那么枚举最大值\(i\),答案就是

\[\sum_{i=1}^k(i^n-(i-1)^n)(i^m-(i-1)^m) \]

看到这个式子果断想到这是一个和\(k\)有关的\(n+m+1\)次多项式,又因为\(k\)很大而\(n,m\)很小直接上插值。

时间复杂度:\(O(n\log n)\)(视\(n,m\)同级)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=3e6+10,P=998244353;
ll n,m,k,pwn[N],pwm[N],f[N],inv[N],pre[N],suf[N],ans;
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
signed main()
{
	freopen("grid.in","r",stdin);
	freopen("grid.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&k);
	ll L=n+m+10;
	for(ll i=1;i<=L;i++){
		pwn[i]=power(i,n);
		pwm[i]=power(i,m);
		f[i]=(f[i-1]+(pwn[i]-pwn[i-1])*(pwm[i]-pwm[i-1])%P)%P;
	}
	inv[0]=inv[1]=1;
	for(ll i=2;i<N;i++)inv[i]=P-inv[P%i]*(P/i)%P;
	for(ll i=1;i<N;i++)inv[i]=inv[i-1]*inv[i]%P;
	pre[0]=k;suf[L]=k-L;suf[L+1]=1;
	for(ll i=1;i<=L;i++)pre[i]=pre[i-1]*(k-i)%P;
	for(ll i=L-1;i>=0;i--)suf[i]=suf[i+1]*(k-i)%P;
	for(ll i=0;i<=L;i++){
		ll w=f[i]*(i?pre[i-1]:1)%P*suf[i+1]%P;
		w=w*inv[i]%P*inv[L-i]%P*(((L-i)&1)?-1:1);
		ans=(ans+w)%P;
	}
	printf("%lld\n",(ans+P)%P);
	return 0;
}

标签:10,suf,插值,ll,网格,leq,YbOJ,ans,include
来源: https://www.cnblogs.com/QuantAsk/p/15896702.html