• codeforces-102501J Counting Trees题解


    题意:给你一个二叉树的中序遍历$(n<=1000000)$,节点值为$1$~$1000000$的整数,可重复。问有多少种树的形态满足每个子树的根节点的权值小于等于该子树所有节点的权值。模$1e9+7$。

    比较显然的一点是如果n个数各不相同,那么答案是1。每次我们找出当前区间的最小的数,把他作为根节点,然后将左右两个区间递归即可。

    如果n个数都相同,那么答案就是第n个斯特林数。

    斯特林数的递推式为$C_{n+1}=C_0C_n+C_1C_{n-1}+……+C_nC_0$

    正好对应了枚举第几个数作为根节点的方案数。

    经过仔细分析,假设当前区间为$(l,r)$,区间$(l,r)$的答案是$ans(l,r)$,最小值为$x$,$x$出现的位置为$x_1,x_2,x_3……,x_cnt$,可以发现,$ans(l,r)={ans}(l,x_1-1)*{ans}(x_1+1,x_2-1)*……*ans (x_{cnt-1}+1,x_{cnt}-1)*ans(x_cnt+1,r)*C_{cnt}$

    所以,我们对区间1~n进行dfs即可。由于每个数最多会造成对两个区间的dfs,所以预处理斯特林数,构建st表以O(1)求区间最小值之后复杂度为$O(n)$。

    具体实现方法为用$vector[x]$存储所有$x$出现的位置。由于我们的区间是从左到右进行dfs的,所以在计算第 $i$个$x$出现的位置时前$i-1$个$x$已经处理完了,我们设置一个$pos[x]$表示当前该处理到第几个$x$就可以了。

      1 #include <bits/stdc++.h>
      2 #include<map>
      3 #define N 2000005
      4 using namespace std;
      5 int n,A[N/2],zz,B[N/2];
      6 const int p=1e9+7;
      7 map<int,int> ma;
      8 int st[N/2][22],xp[N/2];
      9 int pos[N/2];
     10 long long jc[N],ni[N];
     11 vector<int> q1[N/2];
     12 long long ksm(long long x,long long z)
     13 {
     14     long long ans=1;
     15     while(z)
     16     {
     17         if(z&1) ans=ans*x%p;
     18         x=x*x%p;    
     19         z>>=1;
     20     }
     21     return ans;
     22 }
     23 long long get_C(int x,int y)
     24 {
     25     if(y>x)return 0;
     26     return jc[x]*ni[y]%p*ni[x-y]%p;
     27 }
     28 long long get_E(int x)
     29 {
     30     return get_C(x*2,x)*ni[x+1]%p*jc[x]%p;
     31 }
     32 int get_mn(int L,int R)
     33 {
     34     int l=xp[R-L+1];
     35     return min(st[L][l],st[R-(1<<l)+1][l]);
     36 }
     37 long long dfs(int L,int R)
     38 {
     39     if(L>=R)return 1;
     40     int x=get_mn(L,R);
     41     long long ans=1;
     42     int len=q1[x].size();
     43     int cnt=0,La=L,nw=pos[x];
     44     while(nw<len&&q1[x][nw]<L) nw++;
     45     
     46     while(nw<len&&q1[x][nw]<=R)
     47     {
     48         cnt++;
     49         ans=ans*dfs(La,q1[x][nw]-1)%p;
     50         La=q1[x][nw]+1;
     51         nw++;
     52     }
     53     nw--;
     54     if(q1[x][nw]<=R&&q1[x][nw]>=L)
     55     {
     56         ans=ans*dfs(q1[x][nw]+1,R)%p;
     57     }
     58     pos[x]=nw+1;
     59     return ans*get_E(cnt)%p;
     60 }
     61 int main(){
     62     // freopen("test.in","r",stdin);
     63 //    freopen("1.out","w",stdout);
     64     scanf("%d",&n);
     65     if(!n)
     66     {
     67         printf("1
    ");
     68         return 0;
     69     }
     70     jc[0]=1,ni[0]=1;
     71     for(int i=1;i<=n*2;i++) jc[i]=jc[i-1]*i%p;
     72     ni[n*2]=ksm(jc[n*2],p-2);
     73     for(int i=n*2-1;i;i--) ni[i]=ni[i+1]*(i+1)%p;
     74     for(int i=1;i<=n;i++)
     75     {
     76         scanf("%d",&A[i]);
     77         if(!ma[A[i]])
     78         {
     79             zz++;
     80             ma[A[i]]=zz;
     81             B[zz]=A[i];
     82         }
     83     }
     84     sort(B+1,B+zz+1);
     85     xp[1]=0;
     86     for(int i=2;i<=n;i++) xp[i]=xp[i>>1]+1;
     87     for(int i=1;i<=zz;i++) ma[B[i]]=i;
     88     for(int i=1;i<=n;i++) A[i]=ma[A[i]];
     89     for(int i=1;i<=n;i++) st[i][0]=A[i],q1[A[i]].push_back(i);
     90     for(int i=1;i<=20;i++)
     91     {
     92         for(int j=1;j<=n;j++)
     93         {
     94             if((j+(1<<i)-1)>n)break;
     95             st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
     96         }
     97     }
     98     printf("%lld
    ",dfs(1,n));
     99     return 0;
    100 }
    101 /*
    102 
    103 10
    104 1 2 3 1 3 2 3 1 2 2
    105 6
    106 3 1 6 2 4 5
    107 */
    View Code
  • 相关阅读:
    设计模式工厂模式
    设计模式原型模式
    Excel自定义格式千分符
    浏览器报:net::ERR_EMPTY_RESPONSE解决方案
    git branch a无法显示远程分支解决办法
    .Net启动程序报错:It was not possible to find any compatible framework version
    自动化测试框架pytest 安装和入门到精通实战
    2020非常全的接口测试面试题及参考答案软件测试工程师没有碰到算我输!
    Python+unittest+requests+excel实现接口自动化测试框架项目实战
    软件测试必学之python+unittest+requests+HTMLRunner编写接口自动化测试集
  • 原文地址:https://www.cnblogs.com/liutianrui/p/14091978.html
Copyright © 2020-2023  润新知