洛谷 P4707 重返现世(kth-max)

题目链接
min-max进行一波扩展可以查询kth-max
min-max看这里
同样设一个容斥函数 k t h − m a x { S } = ∑ T ⊆ S F ( ∣ T ∣ ) m i n { T } kth-max\{S\}=\sum_{T\subseteq S}F(|T|)min\{T\} kthmax{S}=TSF(T)min{T}
还是一样的列出每个min的出现次数
F ( x ) = ∑ i = 0 x ( x i ) f ( i + 1 ) F(x)=\sum_{i=0}^{x}{x\choose i}f(i+1) F(x)=i=0x(ix)f(i+1)
显然大函数为第k大出现一次
[ x = = k − 1 ] = ∑ i = 0 x ( x i ) f ( i + 1 ) [x==k-1]=\sum_{i=0}^{x}{x\choose i}f(i+1) [x==k1]=i=0x(ix)f(i+1)
二项式反演得
f ( x + 1 ) = ∑ i = 0 x ( − 1 ) x − i ( x i ) F ( i ) f(x+1)=\sum_{i=0}^{x}(-1)^{x-i}{x\choose i}F(i) f(x+1)=i=0x(1)xi(ix)F(i)
f ( x + 1 ) = ∑ i = 0 x ( − 1 ) x − i ( x i ) [ i = = k − 1 ] f(x+1)=\sum_{i=0}^{x}(-1)^{x-i}{x\choose i}[i==k-1] f(x+1)=i=0x(1)xi(ix)[i==k1]
f ( x + 1 ) = ( − 1 ) x − k + 1 ( x k − 1 ) f(x+1)=(-1)^{x-k+1}{x \choose k-1} f(x+1)=(1)xk+1(k1x)
f ( x ) = ( − 1 ) x − k ( x − 1 k − 1 ) f(x)=(-1)^{x-k}{x-1 \choose k-1} f(x)=(1)xk(k1x1)
k t h − m a x { S } = ∑ T ⊆ S ( − 1 ) ∣ T ∣ − k ( ∣ T ∣ − 1 k − 1 ) m i n { T } kth-max\{S\}=\sum_{T\subseteq S}(-1)^{|T|-k}{|T|-1 \choose k-1}min\{T\} kthmax{S}=TS(1)Tk(k1T1)min{T}
这样子就可以把kth-max转化成min
很显然每个min的期望贡献都是集合概率和的倒数,我们可以放一下最后求
先求一下 ∑ T ⊆ S ( − 1 ) ∣ T ∣ − k ( ∣ T ∣ − 1 k − 1 ) \sum_{T\subseteq S}(-1)^{|T|-k}{|T|-1 \choose k-1} TS(1)Tk(k1T1)
考虑DP转移
假设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前 i i i种中选出一个集合使其概率为 j j j ∑ T ⊆ S ( − 1 ) ∣ T ∣ − k ( ∣ T ∣ − 1 k − 1 ) \sum_{T\subseteq S}(-1)^{|T|-k}{|T|-1 \choose k-1} TS(1)Tk(k1T1)
显然对于第i个有两种情况,选或者不选
不选的话很简单 d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] dp[i][j][k]=dp[i-1][j][k] dp[i][j][k]=dp[i1][j][k]
选的话有点小问题,可以发现虽然 i i i i − 1 i-1 i1转移, j j j j − p i j-p_i jpi转移很套路,但是新加进来一个数以后集合大小增加了1,就需要稍微推一下了
每次大小增加1,正负性就会发生改变
根据组合数的递推式, ( ∣ T ∣ − 1 k − 1 ) = ( ∣ T ∣ − 2 k − 1 ) + ( ∣ T ∣ − 2 k − 2 ) {|T|-1 \choose k-1}={|T|-2 \choose k-1}+{|T|-2 \choose k-2} (k1T1)=(k1T2)+(k2T2)
然后正负性与 ∣ T ∣ , k |T|,k T,k都有关,所以等式后第一个的贡献是负的,而第二个的贡献是正的
也就是 d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − p i ] [ k − 1 ] − d p [ i − 1 ] [ j − p i ] [ k ] dp[i][j][k]=dp[i-1][j-p_i][k-1]-dp[i-1][j-p_i][k] dp[i][j][k]=dp[i1][jpi][k1]dp[i1][jpi][k]
边界条件的话 d p [ i ] [ 0 ] [ 0 ] = 1 dp[i][0][0]=1 dp[i][0][0]=1,这个并不是唯一的,但是按照这样子赋有实际意义:考虑上面那个容斥函数,我们只有一个空集,所以这里的 ∑ T ⊆ S ( − 1 ) ∣ T ∣ − k ( ∣ T ∣ − 1 k − 1 ) = 1 \sum_{T\subseteq S}(-1)^{|T|-k}{|T|-1 \choose k-1}=1 TS(1)Tk(k1T1)=1
然后只是从i-1和i转移过来,所以开个滚动数组优化一下空间
统计答案的时候乘上概率的逆元就是答案了
代码如下:

#include
#define mod 998244353
using namespace std;

long long kasumi(long long a,long long b)
{
	long long ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}

long long dp[2][20000][12];
int p[2000];
int n,m,k,pre=0,now=1;

int main()
{
	scanf("%d%d%d",&n,&k,&m);
	k=n-k+1;
	now=1;
	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
	dp[0][0][0]=1;
	now=1,pre=0;
	for(int i=1;i<=n;i++)
	{
		dp[now][0][0]=1;
		for(int j=0;j<=m;j++)
		{
			for(int h=0;h<=k;h++)
			{
				dp[now][j][h]=dp[pre][j][h];
				if(j>=p[i]&&h!=0)
				{
					dp[now][j][h]=(dp[now][j][h]+(dp[pre][j-p[i]][h-1]-dp[pre][j-p[i]][h]+mod)%mod)%mod;
				}
			}
		}
		now^=1,pre^=1;
	}
	long long ans=0;
	for(int i=1;i<=m;i++)
	{
		ans+=dp[pre][i][k]*kasumi(i,mod-2)%mod;
		ans%=mod;
	}
	printf("%lld\n",ans*m%mod);
}

你可能感兴趣的:(minmax容斥,kth-max,洛谷,DP)