zoukankan      html  css  js  c++  java
  • 【模拟7.14】B. 熟练剖分(tree) (概率DP)

    一道概率神题,考试时没读清题考完看了学长的玄学题解看了好几个小时

    首先f[i][j]表示在点 i 为根的子树中,向下最长轻链长度小于等于 j 的概率。

    首先递归下去并求出子树大小,然后枚举重儿子,枚举该点最长轻链长度,再次枚举儿子节点并逐个

    假设当前枚举的重儿子是to1,枚举到儿子节点to2,x最长轻链长度为k,设gs为v(to2)之前考虑的儿子中最长轻链长度为k的概率如果v(to1)=v(to2)即v(to2)为重儿子,则设fs为以v(to2)为根的子树最长轻链长度为k的概率:

    h[k]=(fs*g[k]%mod+gs*f[to2][k]%mod-gs*fs+mod)%mod;     

    如果v(to2)是轻儿子,则设fs为以v(to2)为根的子树最长轻链长度为k-1的概率,

    h[k]=(fs*g[k]%mod+gs*f[to2][k-1]%mod-gs*fs+mod)%mod;

    只是x与to2相连的这条边为轻链所以有减1,值得提醒的一点是这里的f[x][k]并不是最终的f[x][k],只是考虑到当前几个儿子时的值,一个儿子一个儿子地向里加。考虑到f数组直接改的话会错,所以用h数组保存,最后加到g数组中清空h,当to1为重儿子这个情况考虑玩后将g数组加到f中去,清空g。当前节点x求完后,此时的f数组并不是前缀和,所以需要再次转化。

    最后求答案时再次将前缀和转化为单个的值

    至于此题为啥求概率却用一堆整数想乘是因为题目要求

    我们发现每一层的1/chu[x]即为分母,所以可以直接乘逆元,而这样的相加不会影响结果

    所以最后i*f[x][i]就是期望。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<string>
      5 #include<algorithm>
      6 #include<vector>
      7 #include<cmath>
      8 #include<stack>
      9 #include<queue>
     10 #define MAXN 3101
     11 #define ll long long
     12 using namespace std;
     13 const ll mod=1e9+7;
     14 struct node{ll to,n;}e[MAXN];
     15 ll head[MAXN],tot;
     16 void add(ll u,ll v){e[++tot].to=v;e[tot].n=head[u];head[u]=tot;}
     17 ll size[MAXN];
     18 ll f[MAXN][MAXN],g[MAXN],h[MAXN];
     19 ll n;ll chu[MAXN];
     20 ll pow(ll x,ll y)
     21 {
     22     ll ans=1;
     23     while(y)
     24     {
     25        if(y&1)ans=(ans*x)%mod;
     26        x=(x*x)%mod;
     27        y>>=1;
     28     }
     29     return ans%mod;
     30 }
     31 void DFS(ll x)
     32 {
     33    size[x]=1;
     34    for(ll i=head[x];i;i=e[i].n)
     35    {
     36        ll to=e[i].to;
     37        DFS(to);
     38        size[x]+=size[to];
     39    } 
     40    ll ppow=pow(chu[x],mod-2ll)%mod;
     41    for(ll i=head[x];i;i=e[i].n)
     42    {
     43        for(ll i=0;i<=size[x]+1;++i)g[i]=1;
     44        for(ll j=head[x];j;j=e[j].n)
     45        { 
     46            ll fs,gs;
     47            ll to1=e[i].to;ll to2=e[j].to;
     48            for(ll k=0;k<=size[to2]+1;++k)
     49            {           
     50                if(to1==to2){
     51                    if(!k)fs=f[to2][k];else fs=f[to2][k]-f[to2][k-1];
     52                    if(!k)gs=g[k];     else gs=g[k]-g[k-1];
     53                    h[k]=(fs*g[k]%mod+gs*f[to2][k]%mod-gs*fs+mod)%mod;          
     54          //          printf("h[%lld]=%lld
    ",k,h[k]);
     55                }
     56                else if(k){
     57                    if(!k)fs=f[to2][k-1];else fs=f[to2][k-1]-f[to2][k-2];
     58                    if(!k)gs=g[k];       else gs=g[k]-g[k-1];
     59                    h[k]=(fs*g[k]%mod+gs*f[to2][k-1]%mod-gs*fs+mod)%mod;
     60                }
     61            }
     62            g[0]=h[0];h[0]=0;
     63            for(ll k=1;k<=size[to2]+1;++k)
     64            {
     65                g[k]=(g[k-1]+h[k])%mod;h[k]=0;
     66            }
     67        }
     68        for(ll j=size[x]+1;j>=1;--j)
     69        {
     70            g[j]=(g[j]-g[j-1]+mod)%mod;//printf("g[%lld]=%lld
    ",j,g[j]);
     71        }
     72        for(ll j=0;j<=size[x]+1;++j)
     73        {
     74            f[x][j]=(f[x][j]+g[j]*ppow%mod)%mod;
     75        //  printf("f[%lld][%lld]=%lld
    ",x,j,f[x][j]);
     76        }
     77        // printf("p=%lld
    ",pow(chu[x],mod-2ll));
     78    }
     79    if(head[x]==0)f[x][0]=1;
     80    for(ll i=1;i<=size[x]+1;++i)
     81    {
     82         f[x][i]=(f[x][i]+f[x][i-1]+mod)%mod;
     83        // printf("f[%lld][%lld]=%lld
    ",x,i,f[x][i]);
     84    }
     85 }
     86 ll ru[MAXN];ll si=1;
     87 int main()
     88 {
     89      scanf("%lld",&n);
     90      for(ll i=1;i<=n;++i){
     91         scanf("%lld",&chu[i]);
     92         for(ll j=1;j<=chu[i];++j){
     93             ll y;
     94             scanf("%lld",&y);
     95             add(i,y);ru[y]++;
     96         }
     97      }
     98      ll root=0;
     99      for(ll i=1;i<=n;++i){
    100         if(ru[i]==0)
    101          root=i;     
    102      }
    103      DFS(root);
    104      ll ans=0;
    105      for(ll i=1;i<=size[root]+1;++i)
    106      {
    107          ans=(ans+i*(f[root][i]-f[root][i-1]%mod)+mod)%mod;
    108      }
    109      printf("%lld
    ",(ans+mod)%mod);
    110 }
    View Code
  • 相关阅读:
    matlab学习笔记之求解线性规划问题和二次型问题
    matlab学习笔记之基础知识(一)
    jQuery中获取特定顺序子元素(子元素种类不定)的方法
    几种常见网页布局设计
    jQuery中删除节点方法remove()、detach()、empty()分析
    jQuery实现复选框全选、全不选、反选问题解析
    window.onload和$(document).ready()比较
    redis+php微博功能的redis数据结构设计总结(四)
    redis+php实现微博功能(三)
    redis+php实现微博功能(二)
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11191427.html
Copyright © 2011-2022 走看看