zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:玩具(概率DP)

    题目描述

      这个故事发生在很久以前,在$IcePrincess ext{_}1968$和$IcePrince ext{_}1968$都还在上幼儿园的时候。
      $IcePrince ext{_}1968$最近迷上了一种玩具,这种玩具中有两种零件:圆球和棍子。棍子的两头可以插在两个圆球上的各一个空洞中,从而将两个圆球连接起来。为了保证玩具的娱乐性,任意一个圆球上的空洞个数总是多于玩具套装中的棍子数。你可以认为圆球是没有体积的,所有棍子的长度均为$1$。
      $IcePrince ext{_}1968$喜欢这样玩这种玩具:他先摸出玩具袋里的一个圆球放在地上,然后重复下面的操作$n-1$次:每次从袋中取出一个圆球和一根棍子,然后等概率的从地上的圆球中选择一个,将该圆球和选择的圆球用棍子连起来,使得新的圆球在选中圆球的正上方。
      $IcePrince ext{_}1968$对自己搭出的艺术品很满意,便决定把这个物品送给$IcePrincess ext{_}1968$作为生日礼物。然而生日礼物是需要包装的,因为默认圆球没有体积,所以$IcePrince ext{_}1968$不用考虑包装盒的长和宽,但是包装盒的高是需要确定的,这里我们假设$IcePrince ext{_}1968$是一个非常节俭的孩子,所以包装盒的高总是等于艺术品的高度。$IcePrince ext{_}1968$想知道自己需要的包装盒的高的期望对质数$p$取模后的值,但他还在上幼儿园,怎么会算呢,于是就请你来帮助他。


    输入格式

      输入文件名为$toy.in$。
      输入数据仅一行,包含两个正整数$n,p$,表示最终的艺术品中圆球的个数和模数$p$。


    输出格式

      输出文件名为$toy.out$。
      输入文件仅一行,一个正整数,表示包装盒的高的期望对质数$p$取模后的值。


    样例

    样例输入:

    3 998244353

    样例输出:

    499122178


    数据范围与提示

    样例解释:

    三个圆球组成的艺术品,高度只可能是$1$或者$2$,所以高度的期望是$1.5$,在模$998244353$下的期望是$499122178$。

    数据范围:

    对于$30\%$的数据,满足$nleqslant 10,pleqslant 1,000,007$;
    对于$50\%$的数据,满足$nleqslant 20$;
    对于$70\%$的数据,满足$nleqslant 50$;
    对于$100\%$的数据,满足$nleqslant 200,pleqslant 1,000,000,007$,$p$是质数。


    题解

    超级神奇的$DP$,先作出如下定义:

      $alpha.$设$dp[i][j]$表示$i$个点的森林,有$j$个点在第一棵树的概率。

      $eta.$设$f[i][j]$表示有$i$个点的树,深度不超过$j$的概率。

      $gamma.$设$g[i][j]$表示有$i$个点的森林,深度不超过$j$的概率。

    那么,先考虑如何求出$dp$数组,有:

    $$dp[i][j]=dp[i-1][j-1] imesfrac{j-1}{i}+dp[i-1][j] imesfrac{i-j}{i}$$

    初始化$dp[1][1]=1$。

    解释一下,式子的前一半是将新加入的点放入了第一棵树,那么它可以接到$(j-1)$个点上, 后一半是将新加入的这个点放入了除第一棵树外的其它树上(也可以新建一棵树),分母是$i$而不是$(i-1)$的是由于这个点可以新建一棵树,也就是相当于跟谁也没有相接。

    接着考虑一个式子:

    $$f[i][j]=g[i-1][j-1]$$

    化个图你就理解了$downarrow$

    $$Downarrow$$

    也就是说,我们加了一个点,让这棵森林中的所有树都连到了这个节点上。

    再来考虑如何求出$g$数组:

    $$g[i][j]=sum limits_{k=1}^if[k][i] imes g[i-1][j] imes dp[i][k]$$

    这相当于是在$i$个点中选取了$k$个点组成第一棵树,剩下$k$个点还是一个森林,$dp[i][k]$相当于是系数,也就是这第一棵树的形态数。

    最后,因为$f$数组的意义是$f[i][j]$有$i$个点的树,深度不超过$j$的概率;所以我们需要知道深度恰好为$j$的概率,即为$f[n][j]-f[n][j-1]$。

    将每一个深度的概率乘上其深度再加和即为答案。

    时间复杂度:$Theta(n^3)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,p;
    long long inv[201];
    long long dp[201][201],f[201][201],g[201][201];
    long long ans;
    long long qpow(long long x,long long y)
    {
    	long long res=1;
    	while(y)
    	{
    		if(y&1)res=res*x%p;
    		x=x*x%p;
    		y>>=1;
    	}
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&p);
    	dp[1][1]=f[1][0]=1;
    	for(int i=1;i<=n;i++)inv[i]=qpow(i,p-2);
    	for(int i=2;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			dp[i][j]=(dp[i-1][j-1]*(j-1)%p+dp[i-1][j]*(i-j)%p)*inv[i]%p;
    	for(int i=0;i<=n;i++)g[0][i]=1;
    	for(int i=1;i<=n;i++)
    		for(int j=0;j<=n;j++)
    		{
    			if(j)f[i][j]=g[i-1][j-1];
    			for(int k=1;k<=i;k++)g[i][j]=(g[i][j]+f[k][j]*g[i-k][j]%p*dp[i][k]%p)%p;
    		}
    	for(int i=1;i<=n;i++)ans=(ans+(f[n][i]-f[n][i-1]+p)%p*i%p)%p;
    	printf("%lld",ans);
    	return 0;
    }

    rp++

  • 相关阅读:
    MYSQL数据类型——字符串类型
    MYSQL——记录长度
    MYSQL数据类型——时间日期类型
    MYSQL数据类型——数值类型
    为什么在 IDEA jsp 中直接使用 out.println 会出错
    花指令行为大赏
    EasyCpp 题解
    [SUCTF2019] hardcpp 题解
    洛谷 P1650 田忌赛马题解
    Dict 协议是什么
  • 原文地址:https://www.cnblogs.com/wzc521/p/11678497.html
Copyright © 2011-2022 走看看