zoukankan      html  css  js  c++  java
  • [bzoj4824][Cqoi2017]老C的键盘

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    老 C 是个程序员。    
    作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序在某种神奇力量的驱使之下跑得非常快。小 Q 也是一个程序员。有一天他悄悄潜入了老 C 的家中,想要看看这个键盘究竟有何妙处。他发现,这个键盘共有n个按键,这n个按键虽然整齐的排成一列,但是每个键的高度却互不相同。聪明的小 Q 马上将每个键的高度用 1 ~ n 的整数表示了出来,得到一个 1 ~ n 的排列 h1, h2,..., hn 。为了回去之后可以仿造一个新键盘(新键盘每个键的高度也是一个 1 ~ n 的排列),又不要和老 C 的键盘完全一样,小 Q决定记录下若干对按键的高度关系。作为一个程序员,小 Q 当然不会随便选几对就记下来,而是选了非常有规律的一些按键对:对于 i =2,3, ... , n,小 Q 都记录下了一个字符<或者>,表示 h_[i/2] < h_i 或者h _[i/2] > h_i 。于是,小 Q 得到了一个长度为n ? 1的字符串,开开心心的回家了。现在,小 Q 想知道满足他所记录的高度关系的键盘有多少个。虽然小 Q 不希望自己的键盘和老 C 的完全相同,但是完全相同也算一个满足要求的键盘。答案可能很大,你只需要告诉小 Q 答案 mod 1,000,000,007 之后的结果即可。
     
    用f[i][j]表示i的子树内第i个点排名第j的方案数,然后枚举子树合并。
    合并的时候,枚举这个子树内多少个插到i前面,剩下的插到后面,并用两个组合数统计一下这样转移的系数即可。
    复杂度看似是n^3  实际上貌似是n^2logn
    #include<iostream>
    #include<cstdio>
    #define MN 1000 
    #define mod 1000000007
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    struct edge{int to,next;}e[MN+5];
    int n,cnt=0,head[MN+5],f[MN+5][MN+5],g[MN+5][MN+5],size[MN+5],p[MN+5],inv[MN+5],t[MN+5][MN+5];
    char st[MN+5];
    inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}
    inline int C(int n,int m){return 1LL*p[n]*inv[m]%mod*inv[n-m]%mod;}
    void Solve(int x)
    {
        size[x]=1;f[x][1]=1;
        if((x<<1)<=n) ins(x,x<<1);
        if((x<<1|1)<=n) ins(x,x<<1|1);
        for(int i=head[x];i;i=e[i].next)
        {
            Solve(e[i].to);size[x]+=size[e[i].to];
            for(int j=1;j<=size[x];++j)
                for(int k=0;k<j;++k)
                    if(st[e[i].to]=='>')
                        t[x][j]=(t[x][j]+1LL*C(j-1,k)*C(size[x]-j,size[e[i].to]-k)%mod*f[e[i].to][k]%mod*f[x][j-k])%mod;
                    else 
                        t[x][j]=(t[x][j]+1LL*C(j-1,k)*C(size[x]-j,size[e[i].to]-k)%mod*g[e[i].to][k+1]%mod*f[x][j-k])%mod;
            for(int j=1;j<=size[x];++j) f[x][j]=t[x][j],t[x][j]=0;
        }
        for(int i=size[x];i;--i) g[x][i]=(g[x][i+1]+f[x][i])%mod;
        for(int i=1;i<=size[x];++i) (f[x][i]+=f[x][i-1])%=mod;
    }
    
    int main()
    {
        n=read();scanf("%s",st+2);
        p[0]=p[1]=inv[0]=inv[1]=1;
        for(int i=2;i<=n;++i) p[i]=1LL*p[i-1]*i%mod,inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
        for(int i=2;i<=n;++i) inv[i]=1LL*inv[i]*inv[i-1]%mod;
        Solve(1);
        printf("%d
    ",f[1][size[1]]);
        return 0;
    }
  • 相关阅读:
    oracle之sqlplus讲解
    oracle数据库--启动和关闭
    linux下使用SSL代理(SSLedge)
    Titanium系列--利用js动态获取当前时间
    Titanium系列--利用Titanium开发android App实战总结
    Titanium系列--我常用的Titanium的快捷键(持续更新中。。)
    Titanium系列--安装Titanium Studio 中的Android SDK,JDK以及环境变量的配置(二)
    Titanium系列--Titanium的简介、Titanium Studio安装和配置(一)
    Happymenu新的开始
    对IEnumerable<T>和IQueryable<T>的一点见解
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4824.html
Copyright © 2011-2022 走看看