「PMOI-2」简单构造题

定义一个长度为(n)的序列(A)的权值为:

[sum_{l=1}^nsum_{r=l}^n f_A(l,r) ]

其中(f_A(l,r)f)就是在(A)的区间([l,r])中,「所有在该区间内出现过的元素出现次数的乘积」再乘上「区间内所有元素的乘积」。

要求构造一个长为(n)的序列,其中每个元素都是([1,m])中的整数,最大化其权值。

她并不会,只好均匀随机(n)([1,m])中的整数组成一个数列,然后输出其权值。

当然,她的这份程序一分都没拿到;但她想知道,生成出的序列期望权值是多少。

为了防止精度问题,答案需要对(998244353)取模。


想到第一步之后就是做烂的套路了...

可以统计每种长度的所有区间的贡献。设(g_n)为所有长度为(i)的区间的贡献,那么答案就是:

[Ans=sum_{i=1}^ng_i(n-i+1)m^{n-i} ]

由于数的位置不同数列就不同,我们可以写出选每种数的(EGF)

[F(x)=sum_{n=0}frac{nx^n}{n!}=sum_{n=0}frac{x^n}{(n-1)!} ]

那么(g)(EGF)就可以表示成:

[G(x)=prod_{i=1}^{m}F(ix)=exp(sum_{i=1}^nln F(ix)) ]

那么求出(ln F(x))的系数之后,第(n)次项系数乘上(sum_{i=1}^mi^n)就是(sum ln F(ix))(n)次项系数。

现在就是做烂了的自然数幂和。写出这个东西的(EGF)

[H(x)=sum_{n=0}(sum_{i=0}^mi^n)frac{x^n}{n!} =sum_{i=0}^msum_{n=0}frac{(ix)^n}{n!} =sum_{i=0}^me^{ix}=frac{e^{(m+1)x}-1}{e^x-1} ]

这里为了方便让(i)(0)开始的,最后求出系数后让(0)次项为(0)即可。但是这里分母的(0)次项为(0),怎么求逆呢?注意到分子的(0)次项也是(0),所以同时给分子分母都除个(x)即可。总复杂度(mathcal{O}(nlog n))

#include<bits/stdc++.h>
#define rg register
#define il inline
#define cn const
#define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
#define fb(i,a,b) for(rg int i=(a),ed=(b);i>=ed;--i)
using namespace std;
typedef cn int cint;
cint maxn = 200010, mod = 998244353, g = 3, invg = (mod+1)/3;
int n, m, fac[maxn] = {1}, ifac[maxn], inv[maxn] = {0, 1};
int F[maxn] = {1}, ln[maxn<<2], G[maxn<<2], ans;
int A[maxn<<2], B[maxn<<2], H[maxn<<2], pw = 1;
int lim, hst, rev[maxn<<2];
il int fpow(int a, int b, int ans = 1){
	for(; b; b >>= 1, a = 1ll*a*a%mod)if(b&1)ans = 1ll*ans*a%mod;
	return ans;
}
il void init(int n){
	lim = 1, hst = 0;
	while(lim < n)lim <<= 1, ++hst;
	fp(i, 1, lim-1)rev[i] = (rev[i>>1]>>1)|((i&1)<<hst-1);
}
il void ntt(int *a, cint &typ){
	fp(i, 1, lim-1)if(i > rev[i])swap(a[i], a[rev[i]]);
	for(rg int md = 1; md < lim; md <<= 1){
		rg int len = md<<1, Gn = fpow(typ ? invg : g, (mod-1)/len);
		for(rg int l = 0; l < lim; l += len){
			for(rg int nw = 0, Pow = 1; nw < md; ++nw, Pow = 1ll*Pow*Gn%mod){
				rg int x = a[l+nw], y = 1ll*Pow*a[l+nw+md]%mod;
				a[l+nw] = (x+y)%mod, a[l+nw+md] = (x-y+mod)%mod;
			}
		}
	}
	if(!typ)return;
	rg int inv = fpow(lim, mod-2);
	fp(i, 0, lim-1)a[i] = 1ll*a[i]*inv%mod;
}
int inv_ary[maxn<<2];
void get_inv(int *a, int *f, int n){
	if(n == 1)return f[0] = fpow(a[0], mod-2), void();
	get_inv(a, f, n+1>>1), init(n*2-1);
	fp(i, 0, n-1)inv_ary[i] = a[i];
	ntt(f, 0), ntt(inv_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*(2-1ll*f[i]*inv_ary[i]%mod+mod)%mod;
	ntt(f, 1);
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)inv_ary[i] = 0;
}
int ln_ary[maxn<<2];
il void get_ln(int *a, int *f, int n){
	get_inv(a, ln_ary, n), init(n*2-1);
	fp(i, 1, n-1)f[i-1] = 1ll*a[i]*i%mod;
	ntt(f, 0), ntt(ln_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*ln_ary[i]%mod;
	ntt(f, 1);
	fb(i, n-1, 1)f[i] = 1ll*f[i-1]*inv[i]%mod;
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)ln_ary[i] = 0;
	f[0] = 0;
}
int exp_ary[maxn<<2];
void get_exp(int *a, int *f, int n){
	if(n == 1)return f[0] = 1, void();
	get_exp(a, f, n+1>>1), get_ln(f, exp_ary, n), init(n*2-1);
	fp(i, 0, n-1)exp_ary[i] = (a[i]-exp_ary[i]+mod)%mod;
	if((++exp_ary[0]) == mod)exp_ary[0] = 0;
	ntt(f, 0), ntt(exp_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*exp_ary[i]%mod;
	ntt(f, 1);
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)exp_ary[i] = 0;
}
int main(){
	cin >> n >> m;
	fp(i, 1, n+1)fac[i] = 1ll*fac[i-1]*i%mod;
	ifac[n+1] = fpow(fac[n+1], mod-2);
	fb(i, n+1, 1)ifac[i-1] = 1ll*ifac[i]*i%mod;
	fp(i, 2, n+1)inv[i] = mod-1ll*(mod/i)*inv[mod%i]%mod;
	
	fp(i, 1, n)F[i] = ifac[i-1];
	get_ln(F, ln, n+1);
	fp(i, 0, n)pw = 1ll*pw*(m+1)%mod, A[i] = 1ll*pw*ifac[i+1]%mod, B[i] = ifac[i+1];
	get_inv(B, H, n+1), init(n*2+1), ntt(H, 0), ntt(A, 0);
	fp(i, 0, lim-1)H[i] = 1ll*H[i]*A[i]%mod;
	ntt(H, 1), H[0] = m;
	fp(i, 1,n)H[i] = 1ll*H[i]*fac[i]%mod;
	fp(i, 0, n)ln[i] = 1ll*ln[i]*H[i]%mod;
	get_exp(ln, G, n+1);
	fp(i, 0, n)G[i] = 1ll*G[i]*fac[i]%mod;
	
	pw = 1;
	fp(i, 1, n)ans = (ans+1ll*i*pw%mod*G[n-i+1])%mod, pw = 1ll*pw*m%mod;
	printf("%lld
", 1ll*ans*fpow(fpow(m, n), mod-2)%mod);
	return 0;
}
原文地址:https://www.cnblogs.com/akura/p/14502349.html