zoukankan      html  css  js  c++  java
  • NOI2013 树的计数

    题目:http://uoj.ac/problem/122

    85%做法:

    动态规划。

    首先重编号,BFS序变成1...n,然后DFS序相应重编号。

    记pos[i]为i号点在DFS中的位置,即pos[d[i]]=i。

    记F[l][r]表示BFS序中l...r号点相同高度时的高度和,G[l][r]表示BFS序中l...r号点相同高度的个数。

    我们要寻找合法的k,使得[r+1][k]作为下一层,然后转移:

    F[r+1][k]+=F[l][r]+G[l][r]

    G[r+1][k]+=G[l][r]

    我们要找到合法的k,k要满足以下条件:

    (1)[l,r]在DFS序中的下一个一定在[1,k]中。

    分析:

    假设A∈[l,r],那么A在DFS序中的下一个B只有下面3种情况:

    这3种情况中,B的高度最多比A多1。

    [k+1,N]的点应该在[r+1,k]那一层下面,如果[l,r]在DFS序中的下一个在[k+1,N]中,就会在[r+1,k]那一层乱入一个[k+1,N]的点,这样是违法的。

    所以这个条件限制了[k+1,N]进入[r+1,k]那一层。

    (2)r+1在DFS序中的上一个在[l,r]中。

    如下面这种情况:

    如果r+1在DFS序中的上一个不在[l,r]那么,r+1就不能另开一层了。

    (3)[r+1,k]在DFS序中的位置是递增的。

    是为了防止这种情况发生:

    时间复杂度O(N^3),然而实际上满足条件的k并不多,可以过85%的数据。

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline void clear(vector<int> *A,int a,int b){int i,j;A->clear();re(i,0,a)re(j,0,b)A[i].push_back(0);}
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=2000;
    
    int N;
    int d[maxN+10],b[maxN+10];
    int bak[maxN+10],pos[maxN+100];
    DB F[maxN+10][maxN+10],G[maxN+10][maxN+10];
    DB sumF,sumG,ans;
    
    int main()
      {
          freopen("count.in","r",stdin);
          freopen("count.out","w",stdout);
            int i,j,k;
            N=gint();
            re(i,1,N)d[i]=gint();
            re(i,1,N)b[i]=gint();
            re(i,1,N)bak[b[i]]=i;
            re(i,1,N)d[i]=bak[d[i]],b[i]=bak[b[i]];
            re(i,1,N)pos[d[i]]=i;
            F[1][1]=1.0,G[1][1]=1.0;
            re(i,1,N)re(j,i,N)
              {
                  if(G[i][j]==0.0)continue;
                  int t=0;
                  re(k,i,j)upmax(t,d[pos[k]+1]);
                  for(k=j+1;k<=N;k++)
                    {
                          if(k<t)continue;
                        if(!(i<=d[pos[j+1]-1] && d[pos[j+1]-1]<=j))break;
                        if(k-1>=j+1 && pos[k]<pos[k-1])break;
                        F[j+1][k]+=F[i][j]+G[i][j];
                        G[j+1][k]+=G[i][j];
                    }
              }
            sumF=sumG=0.0;
            re(i,1,N)sumF+=F[i][N],sumG+=G[i][N];
            ans=(sgn(sumG)==0)?0.0:sumF/sumG;
            PF("%0.3lf
    ",ans);
      }
    View Code

    100%做法:

    动态规划。

    首先重编号,BFS序变成1...n,然后DFS序相应重编号。

    记pos[i]为i号点在DFS中的位置,即pos[d[i]]=i。

    记h[i]为第i号点的期望高度。

    容易知道h[1]为1,h[2]为2

    我们按照BFS序从小到大枚举1到N,我们知道i号点和i-1号点高度相差0或1,且只能出现在下面蓝色框(i-1号点右边的兄弟),红色框(i-1号点左边兄弟的儿子,此时蓝色框为空)和绿色框中(i-1号点的儿子,此时蓝色框和红色框为空)。

    1.pos[i-1]>pos[i]

           i号点一定在红色框中,所以h[i]=h[i-1]+1

    2.pos[i-1]<pos[i]

           2.1 pos[i-1]+1!=pos[i]

                i号点一定在蓝色框中。

                如果i号点在绿色框中,那么i一定是i-1的第一个儿子,这样的话pos[i-1]+1=pos[i],矛盾,所以i号点一定在蓝色框中。

                所以h[i]=h[i-1]

           2.2 pos[i-1]+1=pos[i]

                考虑绿色框,我们想要i号点在绿色框中就必须保证蓝色框和红色框为空。怎么保证呢?就是[1..i-1]号点在DFS序中的下一个都在[1..i]中。

                2.2.1  [1..i-1]号点在DFS序中的下一个都在[1..i]中。

                         这时候i号点既可以在绿色框中也也可以在蓝色框中,所以h[i]=h[i-1]或h[i]=h[i-1]+1

                         因为这两种情况等概率,所以h[i]=h[i-1]+0.5

               2.2.2   [1..i-1]号点在DFS序中的下一个并不都在[1..i]中。

                        这时候i号点只能在蓝色框,所以h[i]=h[i-1]

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline void clear(vector<int> *A,int a,int b){int i,j;A->clear();re(i,0,a)re(j,0,b)A[i].push_back(0);}
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=200000;
    
    int N;
    int d[maxN+10],b[maxN+10];
    int bak[maxN+10],pos[maxN+10];
    DB h[maxN+10];
    
    int main()
      {
          freopen("count.in","r",stdin);
          freopen("count.out","w",stdout);
          int i;
          N=gint();
          re(i,1,N)d[i]=gint();
          re(i,1,N)b[i]=gint();
          re(i,1,N)bak[b[i]]=i;
          re(i,1,N)d[i]=bak[d[i]],b[i]=bak[b[i]];
          re(i,1,N)pos[d[i]]=i;
          int t=0;
          h[1]=1.0;
            upmax(t,d[pos[1]+1]);
          h[2]=2.0;
          upmax(t,d[pos[2]+1]);
          re(i,3,N)
            {
              if(pos[i-1]>pos[i])
                h[i]=h[i-1]+1.0;
              else
                if(pos[i-1]+1!=pos[i])
                  h[i]=h[i-1];
                else
                  if(t<=i)
                    h[i]=h[i-1]+0.5;
                          else
                            h[i]=h[i-1];
                    upmax(t,d[pos[i]+1]);
                }
          PF("%0.3lf
    ",h[N]);
          return 0;
      }
    View Code

                         

                

           

  • 相关阅读:
    中海洋朗讯杯比赛总结[2014年12月]
    青理工ACM比赛总结和反思[2014年11月]
    程序员技术练级攻略
    一天能学会的计算机技术
    UVa 1597
    回滚机制
    超时和重试机制
    降级特技
    限流详解
    隔离术
  • 原文地址:https://www.cnblogs.com/maijing/p/4682277.html
Copyright © 2011-2022 走看看