zoukankan      html  css  js  c++  java
  • Luogu P6633 [ZJOI2020] 抽卡

    其实我只是来写一发暴力70pts的DP的说,正解拉格朗日反演牛顿迭代什么的根本策不懂

    恭喜彩笔hl666再次因为快速幂忘记返回值调了快一个小时

    这种关于轮次的求期望类似于[ZJOI2019]麻将的方法,考虑第(i)轮对答案的贡献就是前(i)轮操作之后都到不了终止状态的概率(集合(End)表示存在(k)个连续的数)

    [ans=sum_{S ot in End} sum_{ige 0} P( ext{经过$i$轮后选出的集合恰好为$S$}) ]

    我们显然可以容斥掉恰好为(S)的情况,即(其中(ext_j)表示是否存在编号为(j)的卡):

    [P( ext{经过$i$轮后选出的集合恰好为$S$})=sum_{Tsubset S} (-1)^{|S|-|T|} (frac{sum_{jin T} ext_j}{m})^i ]

    带回原式子就有:

    [ans=sum_{S ot in End} sum_{ige 0} sum_{Tsubset S} (-1)^{|S|-|T|} (frac{sum_{jin T} ext_j}{m})^i\ =sum_{S ot in End} sum_{Tsubset S} (-1)^{|S|-|T|} frac{m}{m-sum_{jin T} ext_j} ]

    我们考虑枚举(sum_{jin T} ext_j),然后构造生成函数

    (w_i(x)=x^{ext_i}-1,G(x)=sum_{S ot in End}prod_{iin S} w_i(x)),则答案为(sum_{i=0}^{m-1} frac{m}{m-i}[x^i]G(x))

    我们发现当(ext_i=0)(w_i(x)=0),否则(w_i(x)=x-1),因此我们只需要考虑选(ext_i=1)的点即可

    设一个DP(f_{i,j})表示前(i)种编号选出(j)(ext_i=1)的卡,且满足这些卡不存在连续(k)个的方案数,转移通过容斥显然是(O(1))

    那么现在(G(x)=sum_{ige 0} f_{n,i} imes (x-1)^i),考虑(O(n^2))求出(f_n)之后用二项式定理展开统计即可

    总体复杂度(O(n^2))(设(n,m)同阶)

    #include<cstdio>
    #include<iostream>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=5005,mod=998244353;
    int n,m,k,x,f[N<<1][N],sz[N<<1],ans,fact[N<<1],inv[N<<1];
    inline void inc(int& x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    inline void dec(int& x,CI y)
    {
    	if ((x-=y)<0) x+=mod;
    }
    inline int quick_pow(int x,int p=mod-2,int mul=1)
    {
    	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
    }
    inline void init(CI n)
    {
    	RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
    	for (inv[n]=quick_pow(fact[n]),i=n-1;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%mod;
    }
    inline int C(CI n,CI m)
    {
    	return 1LL*fact[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int main()
    {
    	RI i,j; for (scanf("%d%d",&m,&k),i=1;i<=m;++i)
    	scanf("%d",&x),++sz[x],n=max(n,x);
    	for (f[0][0]=i=1;i<=n;++i)
    	{
    		for (j=0;j<=sz[i-1];++j) f[i][j]=f[i-1][j];
    		if (!sz[i]) sz[i]+=sz[i-1]; else
    		{
    			for (sz[i]+=sz[i-1],j=1;j<=sz[i];++j)
    			{
    				inc(f[i][j],f[i-1][j-1]);
    				if (j>=k&&sz[i]-sz[i-k]==k)
    				dec(f[i][j],f[i>k?i-k-1:0][j-k]);
    			}
    		}
    	}
    	for (init(n),i=0;i<m;++i)
    	{
    		int ret=0; for (j=i;j<=n;++j)
    		if ((j-i)&1) dec(ret,1LL*C(j,i)*f[n][j]%mod);
    		else inc(ret,1LL*C(j,i)*f[n][j]%mod);
    		inc(ans,1LL*m*quick_pow(m-i)%mod*ret%mod);
    	}
    	return printf("%d",ans),0;
    }
    
  • 相关阅读:

    梯度下降法
    维特比算法
    分治法
    动态规划
    hadoop学习视频
    Java深拷贝浅拷贝
    Android NDK r8 Cygwin CDT 在window下开发环境搭建 安装配置与使用 具体图文解说
    Linux高性能server编程——定时器
    OpenGL进阶演示样例1——动态画线(虚线、实线、颜色、速度等)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13396040.html
Copyright © 2011-2022 走看看