「PMOI-2」简单构造题
定义一个长度为\(n\)的序列\(A\)的权值为:
\[\sum_{l=1}^n\sum_{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}^n\ln 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}^m\sum_{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}(n\log 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\n", 1ll*ans*fpow(fpow(m, n), mod-2)%mod);
return 0;
}