[bzoj4824][洛谷P3757][Cqoi2017]老C的键盘

Description

老 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 之后的结果即可。

Input

输入共 1 行,包含一个正整数 n 和一个长度为 n ? 1 的只包含<和>的字符串,分别表示键

盘上按键的数量,和小 Q 记录的信息,整数和字符串之间有一个空格间隔。

Output

输出共 1 行,包含一个整数,表示答案 mod 1,000,000,007后的结果。

Sample Input

5 <>><

Sample Output

3

共5个按键,第1个按键比第2个按键矮,第1个按键比第3个按键高,第2个按键比第4个

按键高,第2个按键比第5个按键矮。

这5个按键的高度排列可以是 2,4,1,3,5 , 3,4,1,2,5 , 3,4,2,1,5 。


简要题解

根据题目描述按键高度关系连边,恰形成一棵二叉树。

树形dp+组合 求解。


想法

看到这道题,我的第一想法是根据高度<或>连边,小的向大的连一条边,形成有向图。

题目要求的便是这个有向图拓扑排序的方案数。

然而这个东西并不太好搞……

于是,又翻题解……

考虑题中所说\(h_i\) 与 \(h_{i/2}\) 比较,发现比较关系可以形成一棵树。

假设某个点的两个子树已各自计算出满足要求的方案数,那这两个子树在各自顺序保持不变时相互顺序怎么改变都仍满足要求。

把当前点插进来只需满足它与左右子的大小关系。

故树形dp,状态f[i][j]表示i在以i为根的子树中排第j位的方案数。

求解f[i][j]时枚举排在i前面的j-1位中有多少位在左子子树(这时要注意i与其左右子的大小关系),记下f[][]的前后缀和,带上组合数瞎搞搞就出来了……

为啥感觉这道题出的有点为树形dp而树形dp呢,感觉不太自然。


代码

(这代码高亮什么情况啊…这么难看)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

#define P 1000000007

using namespace std;

typedef long long ll;
const int N = 105;

int d[N],f[N][N],sum[2][N][N];
int size[N];
int n;

int C[N][N];
void getC(){
    C[0][0]=1;
    for(int i=1;i<=n;i++){
        C[i][0]=1;
        for(int j=1;j<i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%P; /**/
        C[i][i]=1;
    }
}

int main()
{
    char ch[N];
    scanf("%d",&n);
    scanf("%s",ch);
    for(int i=2;i<=n;i++)
        d[i]=(ch[i-2]==‘>‘);

    getC();
    //dp
    for(int i=n;i>0;i--){
        if(i*2>n){ //leaf
            f[i][1]=sum[0][i][1]=sum[1][i][1]=1;
            size[i]=1;
            continue;
        }
        if(i*2+1>n){ //single son
            size[i]=size[i*2]+1;
            for(int j=1;j<=size[i];j++){
                if(d[i<<1]) f[i][j]+=sum[0][i<<1][j-1];
                else f[i][j]+=sum[1][i<<1][j];
            }
            for(int j=1;j<=size[i];j++)
                sum[0][i][j]=((ll)sum[0][i][j-1]+f[i][j])%P;
            for(int j=size[i];j>0;j--)
                sum[1][i][j]=((ll)sum[1][i][j+1]+f[i][j])%P;
            continue;
        }
        size[i]=size[i*2]+size[i*2+1]+1; //double son
        for(int j=1;j<=size[i];j++){
            for(int k1=0;k1<j && k1<=size[i<<1];k1++){
                int k2=j-1-k1,s1,s2;
                if(k2>size[i*2+1]) continue;
                if(d[i<<1]) s1=sum[0][i<<1][k1];
                else s1=sum[1][i<<1][k1+1];
                if(d[(i<<1)+1]) s2=sum[0][(i<<1)+1][k2];
                else s2=sum[1][(i<<1)+1][k2+1];
                f[i][j]=((ll)f[i][j]+(ll)((((ll)s1*s2)%P*C[j-1][k1])%P*C[size[i]-j][size[i<<1]-k1])%P)%P;
            }
        }
        for(int j=1;j<=size[i];j++)
            sum[0][i][j]=((ll)sum[0][i][j-1]+f[i][j])%P;
        for(int j=size[i];j>0;j--)
            sum[1][i][j]=((ll)sum[1][i][j+1]+f[i][j])%P;
    }

    printf("%d\n",sum[0][1][size[1]]);

    return 0;
}

原文地址:https://www.cnblogs.com/lindalee/p/8447971.html

时间: 2024-10-11 10:17:18

[bzoj4824][洛谷P3757][Cqoi2017]老C的键盘的相关文章

Luogu P3757 [CQOI2017]老C的键盘

题目描述 老C的键盘 题解 显然对于每个数 x 都有唯一对应的 \(x/2\) , 然而对于每个数 x 却可以成为 \(x*2\) 和 \(x*2+1\) 的对应数 根据这一特性想到了啥??? 感谢leo101的友情点拨 二叉树!!! 所以可以把 x/2 看做是 x的父亲, 1 显然就是根 可以把 < 看作是由父亲连向儿子的有向边, > 看作是儿子连向父亲的有向边 所以就是求这棵树的拓扑序的方案数就好了!!! 考虑当前节点的两棵子树都已处理完的时候 在满足和 当前节点的关系的同时, 两颗子树在

[bzoj4823][洛谷P3756][Cqoi2017]老C的方块

Description 老 C 是个程序员. 作为一个懒惰的程序员,老 C 经常在电脑上玩方块游戏消磨时间.游戏被限定在一个由小方格排成的R行C列网格上 ,如果两个小方格有公共的边,就称它们是相邻的,而且有些相邻的小方格之间的公共边比较特殊.特殊的公共边排 列得有很强的规律.首先规定,第1行的前两个小方格之间的边是特殊边.然后,特殊边在水平方向上每4个小方格为 一个周期,在竖直方向上每2个小方格为一个周期.所有的奇数列与下一列之间都有特殊边,且所在行的编号从左到 右奇偶交替.下图所示是一个R =

[BZOJ4824][CQOI2017]老C的键盘(树形DP)

4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 193  Solved: 149[Submit][Status][Discuss] Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也是一个程序员.有一天他悄悄潜入了老 C 的家中,想要看看这个 键盘究竟有何妙

[CQOI2017]老C的键盘

[CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ f[i][j]=\sum f[sn_1][k]*f[sn_2][q] \] 需要判断一下\(k,q\)与\(j\)的关系满不满足题意就行了. 但是这样的答案显然不对,因为有些权值可能多次出现. 换句话说,有些权值可能没有出现.所以我们就用那个经典的容斥,枚举颜色数上界. 设\(g[s]\)表示颜色

[bzoj4815] [洛谷P3700] [Cqoi2017] 小Q的表格

Description 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理. 每当小Q不知道如何解决时,就只好向你求助.为了完成任务,小Q需要列一个表格,表格 有无穷多行,无穷多列,行和列都从1开始标号.为了完成任务,表格里面每个格子都填了 一个整数,为了方便描述,小Q把第a行第b列的整数记为f(a,b),为了完成任务,这个表格要 满足一些条件: (1)对任意的正整数a,b,都要满足f(a,b)=f(b,a): (2)对任意的正整数a,b,都要 满

BZOJ 4824: [Cqoi2017]老C的键盘

Description 上一题弱化版,\(n\leqslant 100\) Solution 树形DP. Code /************************************************************** Problem: 4824 User: BeiYu Language: C++ Result: Accepted Time:188 ms Memory:18580 kb *******************************************

【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘

[BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战不同关卡的顺序是一个很大的问题.有n–1个对于挑战关卡的限制,诸如第i个关卡必须在第j个关卡前挑战,或者完成了第k个关卡才能挑战第l个关卡.并且,如果不考虑限制的方向性,那么在这n–1个限制的情况下,任何两个关卡都存在某种程度的关联性.即,我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集

约数和问题(codevs2606&amp;amp;&amp;amp;洛谷2424)

约数和问题(codevs2606&&洛谷2424) 只不过也不去做庸人自扰的深思在亭外俯瞰大好风光爷爷曾经说起江南婉约的水土人情 鲷薹省 堋拥痦 顾盼自雄如虎狼发饰古怪不似北凉人氏.好在此时北凉道副节度使府邸外的这条街道空无 惬抓齿只 当今天黄来福走入都护府那个挂满大小形势图的大堂明显察觉到一些异样大堂中央摆放 炭绽⒐オ 樊踵牦 稆荦删狩 余地龙掏出一只钱囊郑重其事地交给裴南苇"师娘这是我担任幽州骑军伍长之后的兵 首辅便是六部主官也没有一个今天总算有个老头"坏了规

洛谷P1220 关路灯

洛谷1220 关路灯 题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯.    为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电.他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯.开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大