P5401 [CTS2019]珍珠

P5401 [CTS2019]珍珠

至少 (k) 对数相同,感觉可以二项式反演,发现不是很好搞。

草为啥这个是算“至少”啊,感觉之前的题都是算“恰好”。

然后想着想着睡着了,天天数数真累啊

睡醒之后改成了,出现次数为奇数的数 (le n-2m)

发现还是不会算,然后改回去了。。。我在干什么啊,真·数数学傻

稍微想了想也没别的方法。

那么至少 (k) 对数相同的情况就必须得攻克。

忽然发现根本不能算 (k) 数相同,而应该算 (k) 数出现次数为偶数,而偶数的数量不少于 (D-(n-2m)) 就一定有解。(就是奇数的数量 (le n-2m)

这个东西没有标号感觉可恶。。。然后就想到了 ( m EGF)

[e^x={1,1,1,1,1,cdots}\ e^{-x}={1,-1,1,-1,1,-1,cdots}\ ]

加一下我们就有了偶数的 ( m EGF)

[dfrac{e^x+e^{-x}}{2}={1,0,1,0,1,0,cdots} ]

发现可以算了,令 (f(k)) 表示 (k) 种数是偶数的情况。

[f(k)=inom{D}{k}[x^n](dfrac{e^x+e^{-x}}{2})^k(e^x)^{D-k} ]

只不过算重是显然的/kk,但是没关系,二项式反演就好了。

(g(k)) 表示恰好 (k) 种数出现了偶数次的方案数

[f(k)=sum_{i=k}^{D}inom{i}{k}g(i)\ g(k)=sum_{i=k}^{D}inom{i}{k}(-1)^{i-k}f(i) ]

发现我们把 (f) 求出来,(g) 就能求出来,由于 (D) 很小,可以枚举所有 (iin [D-(n-2m),D])(g(i)) ,加起来就是答案了。

看到了一丝希望,开始搞 (f)

40min later:希 望 破 灭 。

woc这个是啥玩意啊。

不想看题解,自己又不会。。。算了,稍微休息下再给一小时。

然后去看了rqy的WC游记。

rqy:T1 大计数,多项式 exp,成功把我推到 rk1,吊打集训队水平。

不能再颓废下去了,不然一生都不可能有rqy的水平了!

既然没啥巧妙的想法就暴力试试吧。

那个 (dfrac{1}{2^k}) 先提出来。

[f(k)=dfrac{dbinom{D}{k}}{2^k}[x^n](e^x+e^{-x})^k(e^x)^{D-k} ]

前面的系数直接忽略,毕竟最后再乘上去是一个可以接受的复杂度。

所以现在要算的是这个东西:

[(e^x+e^{-x})^{k}e^{(D-k)x} ]

之所以说是暴力,因为,我 想 把 前 面 那 个 (k) 次 方 二 项 式 定 理 展 开。貌似也不怎么暴力

[e^{(D-k)x}sum_{i=0}^{k}inom{k}{i}e^{xi}cdot e^{-x(k-i)}\ =e^{(D-k)x}sum_{i=0}^{k}inom{k}{i}e^{(2i-k)x}\ =sum_{i=0}^{k}inom{k}{i}e^{(D+2i-2k)x} ]

因为

[e^{cx}={1,c,c^2,c^3,cdots} ]

现在需要的是对于每一个 (kin [0,D]) 算出 ([x^n])

惊奇的发现居然是直接相加的,也就是说直接把 ([x^n]) 提出来,不用管其余的次数了(之前一直没法下手就是因为还有别的次数在,要卷积 (D) 次)

感觉这个东西可以直接卷积了

[sum_{i=0}^{k}inom{k}{i}dfrac{(D+2i-2k)^n}{n!} ]

由于 ( m EGF) 最后还得乘 (n!) ,直接消掉算了,记得最后别多乘。

[sum_{i=0}^{k}inom{k}{i}(D+2i-2k)^n\ =k!sum_{i=0}^{k}dfrac{1}{i!}dfrac{(D-2(k-i))^n}{(k-i)!} ]

直接卷积即可。

特别鸣谢:rqy,您的游记鼓舞了我,终于切了这道CTS数数题

实现的时候注意统计答案的时候,(D-(n-2m)) 要和 (0)(max) ,还好出题人只卡了 (4) 分,如果是考场上要完蛋啊


以下部分为自己推卷积,可以跳过不看。

主要就是 (f o g) 的部分了。

[g(k)=sum_{i=k}^{D}inom{i}{k}(-1)^{i-k}f(i)\ =dfrac{1}{k!}sum_{i=k}^{D}f(i)i!dfrac{(-1)^{i-k}}{(i-k)!}\ =dfrac{1}{k!}sum_{i=k}^{D}A_iB_{i-k} ]

差卷积不能每次都这么推啊,还是找个通式记下来算了。

(C_i=B_{n-i})

[ ext{原式}=dfrac{1}{k!}sum_{i=k}^{D}A_{i}C_{n-i+k} ]

所以 (g(k)=dfrac{1}{k!}[x^{n+k}](A*C))

// Problem: P5401 [CTS2019]珍珠
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5401
// Memory Limit: 500 MB
// Time Limit: 1000 ms

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return f?x:-x;
}

const int N=100005;
const int M=N<<2;
#define mod 998244353

namespace math{
int fac[N],ifc[N],inv[N];
inline int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
inline int comb(int n,int m){return n<m?0:1ll*fac[n]*ifc[m]%mod*ifc[n-m]%mod;}
void initmath(const int&n=N-1){
	fac[0]=1;for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%mod;
	ifc[n]=qpow(fac[n],mod-2);for(int i=n-1;i>=0;--i)ifc[i]=1ll*(i+1)*ifc[i+1]%mod;
	inv[1]=1;for(int i=2;i<=n;++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
}
using namespace math;

namespace poly{

int rev[M],lg,lim;
void init_poly(const int&n){
	for(lg=0,lim=1;lim<n;++lg,lim<<=1);
	for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
}
void NTT(int*a,int op){
	for(int i=0;i<lim;++i)
		if(i>rev[i])swap(a[i],a[rev[i]]);
	const int g=op?3:inv[3];
	for(int i=1;i<lim;i<<=1){
		const int wn=qpow(g,(mod-1)/(i<<1));
		for(int j=0;j<lim;j+=i<<1){
			int w0=1;
			for(int k=0;k<i;++k,w0=1ll*w0*wn%mod){
				const int X=a[j+k],Y=1ll*w0*a[i+j+k]%mod;
				a[j+k]=(X+Y)%mod,a[i+j+k]=(X-Y+mod)%mod;
			}
		}
	}
	if(op)return;const int ilim=qpow(lim,mod-2);
	for(int i=0;i<lim;++i)a[i]=1ll*a[i]*ilim%mod;
}
#define clr(a,n) memset(a,0,sizeof(int)*(n))
#define cpy(a,b,n) memcpy(a,b,sizeof(int)*(n))
void poly_mul(int*f,int*g,int*ans,int n,int m){
	static int A[M],B[M];init_poly(n+m);
	cpy(A,f,n),clr(A+n,lim-n),NTT(A,1);
	cpy(B,g,m),clr(B+m,lim-m),NTT(B,1);
	for(int i=0;i<lim;++i)ans[i]=1ll*A[i]*B[i]%mod;
	NTT(ans,0);
}

}

int D,n,m,f[M],g[M],ans;

signed main(){
	initmath();
	D=read(),n=read(),m=read();
	for(int i=0;i<=D;++i)f[i]=ifc[i];
	for(int i=0;i<=D;++i)g[i]=(1ll*qpow(D-2*i,n)*ifc[i]%mod+mod)%mod;
	poly::poly_mul(f,g,f,D+1,D+1);
	for(int i=0;i<=D;++i)f[i]=1ll*f[i]*fac[i]%mod;
	for(int i=0,j=1;i<=D;++i,j=1ll*j*inv[2]%mod)f[i]=1ll*comb(D,i)*j%mod*f[i]%mod;
	
	for(int i=0;i<=D;++i)f[i]=1ll*f[i]*fac[i]%mod;
	for(int i=0;i<=D;++i)g[i]=i&1?mod-ifc[i]:ifc[i];
	reverse(g,g+D+1);
	poly::poly_mul(f,g,f,D+1,D+1);
	for(int i=0;i<=D;++i)g[i]=1ll*ifc[i]*f[D+i]%mod;
	
	for(int i=max(0,D-(n-2*m));i<=D;++i)ans=(ans+g[i])%mod;
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/zzctommy/p/14268946.html