欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

【洛谷P4707】重返现世【扩展Min-Max容斥】【dp】

发布时间:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【洛谷P4707】重返现世【扩展Min-Max容斥】【dp】 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

传送门

题意:NNN种物品,每次第iii种产生概率为piM\frac{p_i}{M}Mpi,∑pi=M\sum p_i=Mpi=M。求生成KKK种不同物品的期望时间 模998244353998244353998244353

N≤1000,M≤10000,N−K≤10N \leq1000,M \leq 10000,N-K\leq10N1000,M10000,NK10

又是神仙题……

套路性地把每个物品出现的时间丢到一个集合SSS里面,我们要求的是集合第N−K+1N-K+1NK+1

而最小是随便求的

所以魔改一下Min-Max容斥

假设存在f(x)f(x)f(x)满足

max⁡k(S)=∑T⊆Sf(∣T∣)min⁡(T)\max_k(S)=\sum_{T \subseteq S}f(|T|)\min(T)kmax(S)=TSf(T)min(T)

考虑第m+1m+1m+1大的数产生的贡献

∑i=0mCmif(i+1)\sum_{i=0}^m C_m^if(i+1)i=0mCmif(i+1)

我们希望第kkk大的数贡献一次 即

[m=k−1]=∑i=0mCmif(i+1)[m=k-1]=\sum_{i=0}^m C_m^if(i+1)[m=k1]=i=0mCmif(i+1)

二项式反演一波

F(m)=[m=k−1],G(i)=f(i+1)F(m)=[m=k-1],G(i)=f(i+1)F(m)=[m=k1],G(i)=f(i+1)

F(m)=∑i=0mCmiG(i)F(m)=\sum_{i=0}^mC_m^iG(i)F(m)=i=0mCmiG(i)

G(m)=∑i=0m(−1)m−iCmiF(i)G(m)=\sum_{i=0}^m(-1)^{m-i}C_m^iF(i)G(m)=i=0m(1)miCmiF(i)

f(m+1)=(−1)m−k+1Cmk−1f(m+1)=(-1)^{m-k+1}C_m^{k-1}f(m+1)=(1)mk+1Cmk1

f(m)=(−1)m−kCm−1k−1f(m)=(-1)^{m-k}C_{m-1}^{k-1}f(m)=(1)mkCm1k1

所以

max⁡k(S)=∑T⊆S(−1)∣T∣−kC∣T∣−1k−1min⁡(T)\max_k(S)=\sum_{T \subseteq S}(-1)^{|T|-k}C_{|T|-1}^{k-1}\min(T)kmax(S)=TS(1)TkCT1k1min(T)

当然是期望下的

子集最小可以随便求,所以考虑前面那坨怎么搞

考虑dp

定义状态dp(i,j,k)dp(i,j,k)dp(i,j,k)表示从前iii个物品选出ppp的和为jjj作为TTT(−1)∣T∣−kC∣T∣−1k−1(-1)^{|T|-k}C_{|T|-1}^{k-1}(1)TkCT1k1的和

考虑转移

不选当前点 即dp(i−1,j,k)dp(i-1,j,k)dp(i1,j,k)

选当前点 即

∑i∈T(−1)∣T∣−kC∣T∣−1k−1\sum_{i\in T}(-1)^{|T|-k}C_{|T|-1}^{k-1}iT(1)TkCT1k1

iii丢掉

∑T(−1)∣T∣−k+1C∣T∣k−1\sum_T(-1)^{|T|-k+1}C_{|T|}^{k-1}T(1)Tk+1CTk1

注意此时的TTT在前i−1i-1i1个中选

由于前后的TTT不统一,无法转移,所以……拆组合数

∑T(−1)∣T∣−k+1C∣T∣−1k−1+∑T(−1)∣T∣−k+1C∣T∣−1k−2\sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-1}+\sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-2}T(1)Tk+1CT1k1+T(1)Tk+1CT1k2

−∑T(−1)∣T∣−kC∣T∣−1k−1+∑T(−1)∣T∣−k+1C∣T∣−1k−2-\sum_T(-1)^{|T|-k}C_{|T|-1}^{k-1}+\sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-2}T(1)TkCT1k1+T(1)Tk+1CT1k2

再次强调是前i−1i-1i1个中选的

所以就是

dp(i,j,k)=dp(i−1,j,k)+dp(i−1,j−pi,k−1)−dp(i−1,j−pi,k)dp(i,j,k)=dp(i-1,j,k)+dp(i-1,j-p_i,k-1)-dp(i-1,j-p_i,k)dp(i,j,k)=dp(i1,j,k)+dp(i1,jpi,k1)dp(i1,jpi,k)

然而还有个让人头大的边界问题

j<pij<p_ij<pi也就是不能选当前点 dp(i,j,k)=dp(i−1,j,k)dp(i,j,k)=dp(i-1,j,k)dp(i,j,k)=dp(i1,j,k)

j=pij=p_ij=pi

如果要选就是从空集转移过来,但空集代进去超过了人类的认知,所以直接用定义算

显然就是∣T∣=1|T|=1T=1

(−1)1−kC0k−1=[k=1](-1)^{1-k}C_0^{k-1}=[k=1](1)1kC0k1=[k=1]

所以dp(i,j,k)=dp(i−1,j,k)+[k=1]dp(i,j,k)=dp(i-1,j,k)+[k=1]dp(i,j,k)=dp(i1,j,k)+[k=1]

j>pij>p_ij>pi正常转移

滚动数组优化一下即可

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> using namespace std; const int MOD=998244353; typedef long long ll; int p[1005],dp[2][10005][15]; inline int qpow(int a,int p) {int ans=1;while (p){if (p&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD;p>>=1;}return ans; } #define inv(x) qpow(x,MOD-2) int main() {int N,K,M;scanf("%d%d%d",&N,&K,&M);K=N-K+1;for (int i=1;i<=N;i++) scanf("%d",&p[i]);int cur=1;for (int i=1;i<=N;i++){for (int j=0;j<p[i];j++)for (int k=1;k<=K;k++)dp[cur][j][k]=dp[cur^1][j][k];for (int k=1;k<=K;k++) dp[cur][p[i]][k]=dp[cur^1][p[i]][k]+(k==1);for (int j=p[i]+1;j<=M;j++)for (int k=1;k<=K;k++)dp[cur][j][k]=((ll)dp[cur^1][j][k]+dp[cur^1][j-p[i]][k-1]-dp[cur^1][j-p[i]][k]+MOD)%MOD;cur^=1;}int ans=0;for (int i=1;i<=M;i++) ans=(ans+(ll)dp[N&1][i][K]*M%MOD*inv(i)%MOD)%MOD;printf("%d",(ans+MOD)%MOD);return 0; }

总结

以上是生活随笔为你收集整理的【洛谷P4707】重返现世【扩展Min-Max容斥】【dp】的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。