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;
}

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

  1. 洛谷 P3757 [CQOI2017]老C的键盘

    题面 luogu 题解 其实就是一颗二叉树 我们假设左儿子小于根,右儿子大于根 考虑树形\(dp\) \(f[u][i]\)表示以\(u\)为根的子树,\(u\)为第\(i\)小 那么考虑子树合并 其 ...

  2. 洛谷P3757 [CQOI2017]老C的键盘

    传送门 首先可以直接把整个序列建成一个完全二叉树的结构,这个应该都看得出来 然后考虑树形dp,以大于为例 设$f[i][j]$表示$i$这个节点在子树中排名第$j$位时的总方案数(因为实际只与相对大小 ...

  3. Luogu P3757 [CQOI2017]老C的键盘

    题目描述 老C的键盘 题解 显然对于每个数 x 都有唯一对应的 \(x/2\) , 然而对于每个数 x 却可以成为 \(x*2\) 和 \(x*2+1\) 的对应数 根据这一特性想到了啥??? 感谢l ...

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

    Description 老 C 是个程序员. 作为一个懒惰的程序员,老 C 经常在电脑上玩方块游戏消磨时间.游戏被限定在一个由小方格排成的R行C列网格上 ,如果两个小方格有公共的边,就称它们是相邻的, ...

  5. 洛谷$P3756\ [CQOI2017]$老$C$的方块 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 看到不能出现给定的讨厌的图形,简单来说就,特殊边两侧的方格不能同时再连方格. 所以如果出现,就相当于是四种方案?就分别炸四个格子. 然后冷静分析一波之后发现 ...

  6. [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数

    4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 218  Solved: 171[Submit][Statu ...

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

    4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 193  Solved: 149[Submit][Statu ...

  8. [CQOI2017]老C的键盘

    [CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ ...

  9. BZOJ4813或洛谷3698 [CQOI2017]小Q的棋盘

    BZOJ原题链接 洛谷原题链接 贪心或树形\(DP\)都可做,但显然\(DP\)式子不好推(因为我太菜了),所以我选择贪心. 很显然从根出发主干走最长链是最优的,而剩下的点每个都需要走两步,所以用除去 ...

随机推荐

  1. ZR8.2 DP

    DP 1CF1101D 我们发现,最终答案一定和质因数有关 我们发现\(w_i <= 2*10^5\)级别的树,他的素因子的个数不会非常多(\(<=10\)) 然后我们就设 gcd是\(d ...

  2. Java虚拟机理解-内存管理

    运行时数据区域 jdk 1.8之前与之后的内存模型有差异,方法区有变化(https://cloud.tencent.com/developer/article/1470519). java的内存数据区 ...

  3. Python8_关于编码解码和utf-8

    关于编码:ASCII码是早期的编码规范,只能表示128个字符.7位二进制数表示 扩展ASCII码,由于ASCII码不够用,ASCII表扩充到256个符号,不同的国家有不同的标准:8位二进制数 Unic ...

  4. python3中map函数

    map函数是Python里面比较重要的函数 map函数后面必须接的是序列(元组/列表/字符串) 在python2中执行一些语句 >>> map(str,[1,2,3,4]) ['1' ...

  5. 在linux下find和grep

    在linux下面工作,有些命令能够大大提高效率.本文就向大家介绍find.grep命令,他哥俩可以算是必会的linux命令,我几乎每天都要用到他们.本文结构如下: find命令 find命令的一般形式 ...

  6. 1044 火星数字 (20 分)C语言

    火星人是以 13 进制计数的: 地球人的 0 被火星人称为 tret. 地球人数字 1 到 12 的火星文分别为:jan, feb, mar, apr, may, jun, jly, aug, sep ...

  7. Elasticsearch调优篇-慢查询分析笔记

    前言 elasticsearch提供了非常灵活的搜索条件给我们使用,在使用复杂表达式的同时,如果使用不当,可能也会为我们带来了潜在的风险,因为影响查询性能的因素很多很多,这篇笔记主要记录一下慢查询可能 ...

  8. Excel如何快速选定指定区域

    在日常办公中我们经常遇见需要选中指定的区域,这样选种比较快捷节省时间,要比用鼠标下拉要方便很多. 1.框选的是起始的位置(A1) 2.终止位置 3.这就是我们所要选中的区域例如(A1:H21) 总结: ...

  9. 30.strftime参数

    附:strftime参数 strftime(format[, tuple]) -> string 将指定的struct_time(默认为当前时间),根据指定的格式化字符串输出 python中时间 ...

  10. 12.pyecharts详细使用教程

    官方数据教程: 柱状图-Bar //导入柱状图-Bar from pyecharts import Bar //设置行名 columns = ["Jan", "Feb&q ...