Loading

P5401 [CTS2019]珍珠

P5401 [CTS2019]珍珠

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

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

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

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

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

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

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

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

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

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

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

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

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

\[f(k)=\binom{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}\binom{i}{k}g(i)\\ g(k)=\sum_{i=k}^{D}\binom{i}{k}(-1)^{i-k}f(i) \]

发现我们把 \(f\) 求出来,\(g\) 就能求出来,由于 \(D\) 很小,可以枚举所有 \(i\in [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}\binom{k}{i}e^{xi}\cdot e^{-x(k-i)}\\ =e^{(D-k)x}\sum_{i=0}^{k}\binom{k}{i}e^{(2i-k)x}\\ =\sum_{i=0}^{k}\binom{k}{i}e^{(D+2i-2k)x} \]

因为

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

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

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

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

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

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

\[\sum_{i=0}^{k}\binom{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\to g\) 的部分了。

\[g(k)=\sum_{i=k}^{D}\binom{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}\)

\[\text{原式}=\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\n",ans);
	return 0;
}
posted @ 2021-01-12 19:36  zzctommy  阅读(193)  评论(0编辑  收藏  举报