• 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;
    }
    
  • 相关阅读:
    c#之IOC框架Autofac
    javascript中实现sleep函数
    C#中基本类型占用字节数
    java中基本类型占用字节数
    hibernate 关系映射之 主键关联一对一
    hibernate 关系映射之 双向外键关联一对一
    hibernate 关系映射之 单向外键关联一对一
    MySQL外键的设置及作用
    SchemaExport
    hibernate 关于session的update方法
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15896702.html
Copyright © 2020-2023  润新知