• 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;
    }
    
  • 相关阅读:
    [算法练习]ZigZag Conversion
    获取所有后缀DDE打开命令
    [算法练习]Add Two Numbers
    获取dll编译时生成的pdb文件的名称
    [转载]定位 C++/CLI 库的加载失败异常
    在C++/CLI环境下,千万不要把普通全局函数当标准C/C++的函数指针传递给native的库使用
    Mono集成中使用api获取当前mono 调用堆栈的方法
    简单对比了一下MonoXml与SystemXml在Unity下的表现
    C++从LPEXCEPTION_POINTERS获取调用堆栈
    遇到doxygen生成的chm文档目录如果有中文是乱码?
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14268946.html
Copyright © 2020-2023  润新知