洛谷P4707 重返现世 kMAX-MIN反演+DP

题目分析

kMAX-MIN反演

设kMAX-MIN反演有反演系数函数 f ( ∣ S ∣ ) f(|S|) f(S),使得

k M A X ( S ) = ∑ T = ̸ ∅ , T ⊂ S f ( ∣ T ∣ ) M I N ( T ) kMAX(S)=\sum_{T =\not \emptyset,T \subset S} f(|T|)MIN(T) kMAX(S)=T≠,TSf(T)MIN(T)

假设 S S S集合里有 n n n个数,分别是 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an,且 a 1 ≤ a 2 ≤ . . . ≤ a n a_1 \leq a_2 \leq ... \leq a_n a1a2...an,那么第 k k k大值为 a n − k + 1 a_{n-k+1} ank+1

M I N ( T ) = a i MIN(T)=a_i MIN(T)=ai T T T,满足 T T T中最小元素为 a i a_i ai,所以有:

∑ i = 0 n − x C n − x i f ( i + 1 ) = [ x = n − k + 1 ] \sum_{i=0}^{n-x} C_{n-x}^i f(i+1)=[x=n-k+1] i=0nxCnxif(i+1)=[x=nk+1]

上二项式反演得到:

f ( x + 1 ) = ∑ i = 0 x ( − 1 ) x − i C x i [ i = k − 1 ] = ( − 1 ) x − k + 1 C x k − 1 f(x+1)=\sum_{i=0}^{x} (-1)^{x-i}C_x^i[i=k-1]=(-1)^{x-k+1}C_x^{k-1} f(x+1)=i=0x(1)xiCxi[i=k1]=(1)xk+1Cxk1

综上, f ( x ) = ( − 1 ) x − k C x − 1 k − 1 f(x)=(-1)^{x-k}C_{x-1}^{k-1} f(x)=(1)xkCx1k1

答案就是

∑ T = ̸ ∅ ( − 1 ) ∣ T ∣ − K C ∣ T ∣ − 1 K − 1 m ∑ i ∈ T p i \sum_{T =\not \emptyset}(-1)^{|T|-K}C_{|T|-1}^{K-1}\frac{m}{\sum_{i \in T}p_i} T≠(1)TKCT1K1iTpim

DP

不难发现本题的 k k k应该转化为第 n − k + 1 n-k+1 nk+1小值,而 n − k ≤ 10 n-k \leq 10 nk10,所以 n − k + 1 ≤ 11 n-k+1 \leq 11 nk+111。再加上 n n n m m m都不大,大胆猜想应该把它们都算进复杂度中。

f ( j , k ) f(j,k) f(j,k)表示,对于当前考虑到的 ∑ i ∈ T p i = j \sum_{i \in T}p_i=j iTpi=j的集合,当 K = k K=k K=k时,它们的容斥系数(反演系数)的和。

一个个考虑每种物品,如果不选择第 i i i种物品: f ( j , k ) + = f ′ ( j , k ) f(j,k)+=f'(j,k) f(j,k)+=f(j,k)

如果选择,首先是 − 1 -1 1的次方改变,这个很好办。然后组合数的问题, C ∣ T ∣ − 1 K − 1 = C ∣ T ∣ − 2 K − 1 + C ∣ T ∣ − 2 K − 2 C_{|T|-1}^{K-1}=C_{|T|-2}^{K-1}+C_{|T|-2}^{K-2} CT1K1=CT2K1+CT2K2,所以综上, f ( j , k ) + = − f ( j − p i , k ) + f ( j − p i , k − 1 ) f(j,k)+=-f(j-p_i,k)+f(j-p_i,k-1) f(j,k)+=f(jpi,k)+f(jpi,k1)

至于边界,是一个被构造了的,很妙的 f ( 0 , 0 ) = 0 , f ( 0 , k ) = − 1 f(0,0)=0,f(0,k)=-1 f(0,0)=0,f(0,k)=1的边界。不过也可以预处理一维的边界啥的。

代码

#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int mod=998244353;
int n,K,m,ans;
int p[1005],inv[10005],f[2][10005][13];

int qm(int x) {return x>=mod?x-mod:x;}
int main()
{
	scanf("%d%d%d",&n,&K,&m);
	K=n-K+1;
	for(RI i=1;i<=n;++i) scanf("%d",&p[i]);
	inv[1]=1;for(RI i=2;i<=m;++i) inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
	for(RI i=1;i<=K;++i) f[0][0][i]=mod-1;
	for(RI i=1,t=1,lim=0;i<=n;++i,t^=1) {
		for(RI j=0;j<=lim;++j)
			for(RI k=1;k<=K;++k) {
				if(!f[t^1][j][k]) continue;
				f[t][j][k]=qm(f[t][j][k]+f[t^1][j][k]);
				f[t][j+p[i]][k+1]=qm(f[t][j+p[i]][k+1]+f[t^1][j][k]);
				f[t][j+p[i]][k]=qm(f[t][j+p[i]][k]-f[t^1][j][k]+mod);
				f[t^1][j][k]=0;
			}
		lim+=p[i];
	}
	for(RI i=1;i<=m;++i) ans=qm(ans+1LL*inv[i]*f[n&1][i][K]%mod);
	ans=1LL*ans*m%mod;
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值