洛谷 P5850 calc加强版 题解

题目传送门

题目大意:这题,但是对于 1 1 1 ~ m m m 内的每个 n n n 都要求解,且 m ≤ 5 × 1 0 5 m\leq 5\times 10^5 m5×105

题解

先不考虑顺序,最后乘 n ! n! n! 即可。

每个元素之多选一个,要选出 n n n 个来,且贡献为他们的乘积,那么生成函数形式就是 ∏ i = 1 k ( 1 + i x ) \prod_{i=1}^k (1+ix) i=1k(1+ix),答案就是 x n x^n xn 的系数。

用付公主的背包的套路,求个 ln ⁡ \ln ln,得到:
ln ⁡ ( 1 + i x ) = − ∑ j = 1 ∞ ( − i x ) j j ln ⁡ ( ∏ i = 1 k ( 1 + i x ) ) = − ∑ i = 1 k ∑ j = 1 ∞ ( − i x ) j j = ∑ j = 1 ∞ ( − 1 ) j − 1 j x j ∑ i = 1 k i j \ln(1+ix)=-\sum_{j=1}^{\infty}\frac {(-ix)^j} j\\ \ln(\prod_{i=1}^k (1+ix))=-\sum_{i=1}^k\sum_{j=1}^{\infty}\frac {(-ix)^j} j=\sum_{j=1}^{\infty}\frac {(-1)^{j-1}} j x^j\sum_{i=1}^k i^j ln(1+ix)=j=1j(ix)jln(i=1k(1+ix))=i=1kj=1j(ix)j=j=1j(1)j1xji=1kij

考虑如何快速求后面的自然数幂和,他的EGF为:
∑ j = 1 ∞ ( ∑ i = 1 k i j ) x j j ! = ∑ i = 1 k ( ∑ j = 1 ∞ i j x j j ! ) = ∑ i = 1 k e i x = 1 − e ( k + 1 ) x 1 − e x \sum_{j=1}^{\infty}(\sum_{i=1}^k i^j) \frac {x^j} {j!}=\sum_{i=1}^k(\sum_{j=1}^{\infty}\frac {i^jx^j} {j!})=\sum_{i=1}^k e^{ix}=\frac {1-e^{(k+1)x}} {1-e^x} j=1(i=1kij)j!xj=i=1k(j=1j!ijxj)=i=1keix=1ex1e(k+1)x

e ( k + 1 ) x e^{(k+1)x} e(k+1)x e x e^x ex 手动泰勒展开一下然后求个逆就可以了。但是要注意,分子分母都没有常数项,所以要同时除以 x x x 再求逆,不然没法求。

最后再求个 exp ⁡ \exp exp 就做完了,代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 1100010
#define mod 998244353
#define bin(x) (1<<(x))
#define MS(f,x) memset(f,0,4<<(x))
#define CP(f,g,x) memcpy(f,g,(x)<<2)

void write(int x){
    
    
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
int n,k,F[maxn],G[maxn];
int ksm(int x,int y){
    
    int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int inv[maxn],w[maxn];void prep(int lg){
    
    int N=bin(lg);
	inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1,wn;i<N;i<<=1){
    
    
		w[i]=1;wn=ksm(3,(mod-1)/(i<<1));
		for(int j=1;j<i;j++)w[i+j]=1ll*w[i+j-1]*wn%mod;
	}
}
int r[maxn],limit;
void InitR(int lg){
    
    for(int i=1;i<bin(lg);i++)r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));}
int add(int x){
    
    return x>=mod?x-mod:x;}
int dec(int x){
    
    return x<0?x+mod:x;}
void ntt(int *f,int lg,int type=0){
    
    
	limit=bin(lg);if(type)reverse(f+1,f+limit);
	for(int i=1;i<limit;i++)if(i<r[i])swap(f[i],f[r[i]]);
	for(int mid=1,t;mid<limit;mid<<=1)for(int j=0;j<limit;j+=(mid<<1))for(int i=0;i<mid;i++)
	{
    
    t=1ll*f[j+i+mid]*w[mid+i]%mod;f[j+i+mid]=dec(f[j+i]-t);f[j+i]=add(f[j+i]+t);}
	if(type)for(int i=0;i<limit;i++)f[i]=1ll*f[i]*inv[limit]%mod;
}
void NTT(int *f,int *g,int ln){
    
    
	int lg=ceil(log2(ln<<1));ntt(f,lg);ntt(g,lg);
	for(int i=0;i<bin(lg);i++)f[i]=1ll*f[i]*g[i]%mod;ntt(f,lg,1);
}
int A[maxn],B[maxn],C[maxn],D[maxn],E[maxn];
void getinv(int *f,int *g,int ln){
    
    
	if(ln==1){
    
    g[0]=ksm(f[0],mod-2);return;}getinv(f,g,ln+1>>1);
	int lg=ceil(log2(ln<<1));MS(A,lg);MS(B,lg);CP(A,f,ln);CP(B,g,ln);
	InitR(lg);ntt(A,lg);ntt(B,lg);for(int i=0;i<bin(lg);i++)B[i]=1ll*B[i]*(2-1ll*A[i]*B[i]%mod+mod)%mod;
	ntt(B,lg,1);CP(g,B,ln);
}
void Dao(int *f,int *g,int ln){
    
    for(int i=0;i<ln-1;i++)g[i]=1ll*f[i+1]*(i+1)%mod;g[ln-1]=0;}
void Jifen(int *f,int *g,int ln){
    
    for(int i=ln-1;i>0;i--)g[i]=1ll*f[i-1]*inv[i]%mod;g[0]=0;}
void getln(int *f,int *g,int ln){
    
    
	int lg=ceil(log2(ln<<1));MS(C,lg);MS(D,lg);
	Dao(f,C,ln);getinv(f,D,ln);NTT(C,D,ln);Jifen(C,g,ln);
}
void getexp(int *f,int *g,int ln){
    
    
	if(ln==1){
    
    g[0]=1;return;}getexp(f,g,ln+1>>1);
	int lg=ceil(log2(ln<<1));MS(E,lg);getln(g,E,ln);
	for(int i=0;i<ln;i++)E[i]=(f[i]-E[i]+mod)%mod;E[0]++;
	NTT(g,E,ln);
}
int fac[maxn],inv_fac[maxn];
void FacInit(){
    
    
	fac[0]=inv_fac[0]=1;
	for(int i=1;i<=n+1;i++){
    
    
		fac[i]=1ll*fac[i-1]*i%mod;
		inv_fac[i]=1ll*inv_fac[i-1]*inv[i]%mod;
	}
}

int main()
{
    
    
	scanf("%d %d",&k,&n);
	prep(ceil(log2(n+1<<1)));FacInit();
	for(int i=0;i<=n;i++)F[i]=inv_fac[i+1];
	getinv(F,G,n+1);
	for(int i=0,prod=(k+1)%mod;i<=n;i++,prod=1ll*prod*(k+1)%mod)
		F[i]=1ll*prod*inv_fac[i+1]%mod;
	NTT(F,G,n+1);
	F[0]=0;
	for(int i=1;i<=n;i++){
    
    
		F[i]=1ll*F[i]*fac[i]%mod*inv[i]%mod;
		if(i-1&1)F[i]=(mod-F[i])%mod;
	}
	for(int i=n+1;i<=maxn-10;i++)F[i]=0;
	memset(G,0,sizeof(G));
	getexp(F,G,n+1);
	for(int i=1;i<=n;i++)write(1ll*G[i]*fac[i]%mod),puts("");
}

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/112595584
今日推荐