[luogu P4707] 重返现世

Description

洛谷题目链接:https://www.luogu.org/problemnew/show/P4707

Solution

前置广义\(\min-\max\)容斥,不懂的可以看看我的min-max容斥学习笔记

那么\(\min\{S\}\)显然是比较好求的,具体的:

\[\min\{S\}=\frac{m}{\sum_{i\in S}p_i} \]

但是注意到\(n\)的范围很大,显然不能用常规做法。

注意到\(k\)很小,可以考虑\(dp\)

\(f_{x,s,k}\)表示当前\(dp\)到前\(x\)个了,选出来的要满足\(\sum p=s\),且为第\(k\)大的系数,因为可以注意到后面的\(\min\)都是一样的,我们这里在\(dp\)当前的\(\min\)被算了多少次,那么这个\(dp\)状态的意义就是前面那一坨系数,即:

\[\sum_{T}(-1)^{|T|-k}\binom{|T|-1}{k-1} \]

并且满足了一堆的条件。

考虑怎么转移这个\(dp\),这里显然是要分情况讨论:

如果不选\(x\),那么转移就很简单了,直接是\(f_{x,s,k}=f_{x-1,s,k}\)

否则就有点复杂了,我们先把式子写出来:

\[f_{x,s,k}=\sum_{T}(-1)^{|T|-k}\binom{|T|-1}{k-1}\\ \]

然后这里的\(\sum p=s\),由于这里硬点\(x\)要选,我们不妨考虑剩下的部分是啥样的:

\[f_{x,s,k}=\sum_{T}(-1)^{|T|+1-k}\binom{|T|}{k-1} \]

注意这里枚举的\(T\)是不含\(x\)的,且\(\sum p=s-p_x\),我们尝试着利用组合数的性质把它展开:

\[\begin{align} f_{x,s,k}&=\sum_{T}(-1)^{|T|+1-k}(\binom{|T|-1}{k-1}+\binom{|T|-1}{k-2})\\ &=-\sum_T(-1)^{|T|-k}\binom{|T|-1}{k-1}+\sum_T(-1)^{|T|-(k-1)}\binom{|T|-1}{(k-1)-1}\\ &=-f_{x-1,s-p_x,k}+f_{x-1,s-p_x,k-1} \end{align} \]

那么我们就可以得到总的转移方程:

\[f_{x,s,k}=f_{x-1,s,k}-f_{x-1,s-p_x,k}+f_{x-1,s-p_x,k-1} \]

边界条件就直接\(f_{x,0,0}=1\)就好了。

注意这里空间复杂度会爆掉,要把\(dp\)的第一维滚掉就好了。

代码真的很好写...

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int mod = 998244353;

int qpow(int a,int x) {
	int res=1;
	for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
	return res;
}

int n,K,m,p[maxn],f[2][10050][12];

int main() {
	read(n),read(K),read(m);K=n-K+1;
	for(int i=1;i<=n;i++) read(p[i]);
	f[0][0][0]=1;
	for(int t=1;t<=n;t++) {
		int i=t&1;
		for(int j=0;j<p[t];j++)
			for(int k=0;k<=K;k++)
				f[i][j][k]=f[i^1][j][k];
		f[i][0][0]=1;
		for(int j=p[t];j<=m;j++)
			for(int k=1;k<=K;k++)
				f[i][j][k]=((f[i^1][j][k]+f[i^1][j-p[t]][k-1])%mod-f[i^1][j-p[t]][k])%mod;
	}
	int ans=0;
	for(int i=1;i<=m;i++) ans=(ans+1ll*f[n&1][i][K]*m%mod*qpow(i,mod-2)%mod)%mod;
	write((ans+mod)%mod);
	return 0;
}
posted @ 2019-03-13 10:37  Hyscere  阅读(126)  评论(0编辑  收藏  举报