hdu 5919 dfs前序遍历计数 笛卡尔树

来源:互联网 发布:java连接sqlserver代码 编辑:程序博客网 时间:2024/06/07 09:46

题意:有n个区间,对于第i个区间[li,ri]有li<=i<=ri,
对于任意1<=L<=i<=R<=n,当前仅当li<=L<=i<=R<=ri时P[i]=min(P[L],P[L+1],…,P[R])

关键应该就是题目的 if and only if 当且仅当,就是指l r必须是pi管理的范围,再大都不是它管理的范围了,那么就是一个区间分治处理和合并了,这能想到和dfs序是一致的,所以用dfs,考虑 对于每个pi 它的左区间 li和 ri 无论你怎么分配其实都是可以得到 一个最小的数 第二小的数,那么就是怎么分配这些数,按理说 如果分配是可行的,那么每个以 P[i] 的i为分界线的区间,两边分治处理的小区间是不会产生冲突的 冲突是指,所有的区间递归的包含一个个更小的区间,而且被包含的区间不能跨过包含区间的pi 其实处理好,每个区间都是一直包含着别的区间,而且必然成立,所以建造笛卡尔树。先根据l最左,r最右排序,递归的找有没有冲突的区间,如果没有区间冲突, 那么区间的数其实你是可以随便放的,所以就是 C(区间总数-1(最小值已固定位置),左边区间的数)*dfs左得到左边内部的方案数(也就是位置的不同)*dfs右(同理)

所有的区间,要么是相互包含的,要么没有交集,不会出现有相交的情况。这个如何解释呢?我们们用反证法,假设区间[li,ri]与[lj,rj]相交,对于li < lj < ri < rj的情况,根据当且仅当的条件,我们可以知道a[ri+1] < a[i],又a[j] < a[ri+1],所以a[j] < a[i],所以lj <= i,区间包含,故与区间相交矛盾,所以不可能出现相交。另外的情况同理可证。

#include <bits/stdc++.h>using namespace std;namespace IO {      const int MX = 4e7; //1e7占用内存11000kb      char buf[MX]; int c, sz;      void begin() {          c = 0;          sz = fread(buf, 1, MX, stdin);      }      inline bool read(int &t) {          while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;          if(c >= sz) return false;          bool flag = 0; if(buf[c] == '-') flag = 1, c++;          for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t * 10 + buf[c] - '0';          if(flag) t = -t;          return true;      }  }  const int N = 1e6+100;const int mod =1e9+7;struct node{    int id,l,r;}s[N+100];typedef long long ll;ll fac[N+100],inv[N+100];int cmp(node a,node b){    if(a.l==b.l) return a.r>b.r;    return a.l<b.l;}ll qpow(ll a,ll b){    ll res=1;    while(b)    {        if(b&1) res*=a,res%=mod;        a*=a;        a%=mod;        b>>=1;    }    return res;}void init(){    fac[0]=1;    for(int i=1;i<=N;i++)        fac[i]=(fac[i-1]*i)%mod;    inv[N]=qpow(fac[N],mod-2);    for(int i=N-1;i>=0;i--)    {        inv[i]=inv[i+1]*(i+1);        inv[i]%=mod;    }}int mark,arr;ll C(ll a,ll b){    if(a<b) return 0;    if(a==b) return 1;    if(b==0) return 1;    a%=mod,b%=mod;    return ((fac[a]*inv[b])%mod*inv[a-b])%mod;}ll dfs(int l,int r){    if(mark==0)        return 0;    if(l>r) return 1;    if(l!=s[arr].l||r!=s[arr].r)    {        mark=0;        return 0;    }    ll res;    node now=s[arr++];    res=(C(now.r-now.l,now.id-now.l)*dfs(now.l,now.id-1))%mod;    res=(res*dfs(now.id+1,now.r))%mod;    return res;}int main(){    ////freopen("in.txt", "r", stdin);      int n,cas=1;    init();    IO::begin();      while(IO::read(n))    {        arr=1;        for (int i = 1; i <= n; i++) IO::read(s[i].l);          for (int i = 1; i <= n; i++) IO::read(s[i].r), s[i].id = i;          sort(s+1,s+n+1,cmp);        mark=1;        printf("Case #%d: %lld\n",cas++,dfs(1,n) );    }}