• 【UOJ 351】新年的叶子


    http://uoj.ac/problem/351

    其实原来看到这题是真的不想做的 毕竟真的特别怕期望题

    后来莫名发现自己打了正解 也是很震惊的2333

    Description

      对于一棵树,每次随机染黑一个叶子(可能会重复染黑),期望多少次后直径变小

    Solution

      第一种R为偶数的情况时:找一个点root所有的直径都经过这个root点,以此点为根

        dpx=R/2的点可能是直径断点,先统计出来个数(x1),把所有dpx=R/2的点按他是root的哪一棵子树分成几个集合

      直径改变了,当且仅当只剩下一个集合的点没有被删完。

      第二种R为奇数的情况时:

      把必经边分成两个集合,集合中的点为dpx=R/2(向下取整)把x1也一样的统计,就成了跟上述情况类似了

      无关点可当做一开始就被删掉了,所以再删掉一个没被删的点的代价就是全部叶子数/还剩的点的个数

      问题转化成:每删除一个剩下的点,求删剩一个集合的期望值

      1 #include <bits/stdc++.h>
      2 #define N 500010
      3 #define Mo 998244353
      4 using namespace std;
      5 long long n,m,ans,jc[N],jcn[N],sum[N];
      6 long long edge[N*2][2],e1[N];
      7 long long a[N],f[N],t;
      8 long long X,maxx,X1,d[N],x1,cnt;
      9 inline long long ksm(long long b,long long p);
     10 inline void init(){
     11     for (register long long i=1;i<=n;++i)
     12         jc[i]=jc[i-1]*(long long)i%Mo;
     13     jcn[n]=ksm(jc[n],Mo-2);
     14     for (register long long i=n-1;i>=0;--i)
     15         jcn[i]=jcn[i+1]*(i+1LL)%Mo;
     16 }
     17 inline long long read(){
     18     char ch=' ';long long x=0,y=1;
     19     for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
     20     if(ch=='-')y=-1,ch=getchar();
     21     for(;ch>='0' && ch<='9';ch=getchar())x=x*10+ch-48;
     22     x=x*y;
     23     return x;
     24 }
     25 inline void Build(long long x,long long y){
     26     ++a[x];++a[y];
     27     edge[++cnt][0]=e1[x];
     28     edge[cnt][1]=y;
     29     e1[x]=cnt;
     30     edge[++cnt][0]=e1[y];
     31     edge[cnt][1]=x;
     32     e1[y]=cnt;
     33 }
     34 inline long long ksm(long long b,long long p){
     35     long long a=b,c=p,ans=1;
     36     while(p>0){
     37         if(p-p/2*2!=0) ans=(ans*b)%Mo;
     38         b=(b*b)%Mo,p=p>>1;    
     39     }
     40     return ans;
     41 }
     42 inline long long calc(long long m,long long n){return jc[m]*jcn[m-n]%Mo*jcn[n]%Mo;}
     43 void dfs(long long x,long long s,long long father){
     44     long long max1=0,t=0,g;
     45     for(register long long i=e1[x];i;i=edge[i][0])
     46         if(edge[i][1]!=father&&f[edge[i][1]]+1>s)
     47             t=s,s=f[edge[i][1]]+1,max1=edge[i][1];
     48         else if(edge[i][1]!=father&&f[edge[i][1]]+1>t)
     49             t=f[edge[i][1]]+1;
     50     if (s+t>ans) ans=s+t;
     51     if (maxx>=s){
     52         if (maxx>s) X=x; else X1=x;
     53         maxx=s;
     54     }
     55     for(register long long i=e1[x];i;i=edge[i][0])
     56         if(edge[i][1]!=father){
     57             if (max1==edge[i][1])
     58                 g=t+1;
     59             else g=s+1;
     60             dfs(edge[i][1],g,x);
     61         }
     62 }
     63 long long dfs1(long long x,long long y,long long father){
     64     long long ans=(!y);
     65     for(long long i=e1[x];i;i=edge[i][0])
     66         if(edge[i][1]!=father)
     67             ans+=dfs1(edge[i][1],y-1,x);
     68     return ans;
     69 }
     70 void dfs2(long long x,long long father){
     71     f[x]=0;
     72     for(long long i=e1[x];i;i=edge[i][0])
     73         if(edge[i][1]!=father)
     74             dfs2(edge[i][1],x),f[x]=max(f[x],f[edge[i][1]]+1);
     75     x1+=(a[x]==1?1:0);
     76 }
     77 inline long long answer(long long m,long long m1){
     78     long long ans=0,ans1=0,t=0;
     79     for (int i=m;i>=0;i--)
     80         sum[i]=(sum[i+1]+m1*ksm(i,Mo-2))%Mo;
     81     for (int j=1;j<=d[0];++j)
     82         for (int i=0;i<=d[j]-1;++i){
     83             ans=(ans+(calc(d[j],i)*jc[m-d[j]+i-1]%Mo*(m-d[j])%Mo)*sum[d[j]-i+1]%Mo*jc[d[j]-i])%Mo;
     84             ans1=(ans1+(calc(d[j],i)*jc[m-d[j]+i-1]%Mo*(m-d[j])%Mo))%Mo;
     85         }
     86     return ans*jcn[m]%Mo;
     87 }
     88 int  main(){
     89     n=read(),jc[0]=1,maxx=1e9,t=0;
     90     for (register long long i=1;i<=n-1;++i)
     91         Build(read(),read());
     92     init();
     93     dfs2(1,0);
     94     dfs(1,0,0);
     95     if (ans&1){
     96         d[0]=2;d[1]=dfs1(X,ans/2,X1);d[2]=dfs1(X1,ans/2,X);
     97         printf("%lld
    ",answer(d[1]+d[2],x1));
     98     }
     99     else{
    100         for(register long long i=e1[X];i;i=edge[i][0])
    101             t+=(d[++d[0]]=dfs1(edge[i][1],ans/2-1,X));
    102         printf("%lld
    ",answer(t,x1));
    103     }
    104     return 0;
    105 }
  • 相关阅读:
    RMQ(非log2储存方法)
    2016年5月份学习记录
    NOIP200504循环
    膜拜acm大牛 虽然我不会这题,但是AC还是没有问题的~(转自hzwer)
    最长公共子序列的长度
    菜鸟,大牛和教主三者的区别(转自hzwer)
    NOIP201205Vigenère密码
    NOIP200503采药
    公路乘车
    NOIP200902分数线划定
  • 原文地址:https://www.cnblogs.com/wjnclln/p/9912954.html
Copyright © 2020-2023  润新知