博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数
阅读量:4622 次
发布时间:2019-06-09

本文共 2929 字,大约阅读时间需要 9 分钟。

4824: [Cqoi2017]老C的键盘

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 218  Solved: 171
[][][]

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 。

HINT

 

Source

 

将原数列建成一颗二叉树。

对于一个节点i,f[i][j]表示节点在子树中排名为j的方案数。

转移的时候枚举每个子树中有多少个在它前面即可。

根据复杂度分析后可得时间复杂度为O(n^2)

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #define ll long long 8 #define mod 1000000007 9 #define maxn 100110 using namespace std;11 inline ll read() {12 ll x=0,f=1;char ch=getchar();13 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;14 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';15 return x*f;16 }17 struct data { int to,nxt,tp;}e[maxn*2];18 int head[maxn],cnt;19 inline void add(int u,int v,int tp) {e[cnt].to=v;e[cnt].nxt=head[u];e[cnt].tp=tp;head[u]=cnt++;}20 ll n,ans,jc[maxn],inv[maxn];21 ll f[maxn][maxn],g[maxn][maxn],sz[maxn],t[maxn][maxn];22 char s[maxn];23 inline ll C(int x,int y){ return jc[x]*inv[y]%mod*inv[x-y]%mod;}24 void dp(int x) {25 sz[x]=1;f[x][1]=1;26 if((x<<1)<=n) add(x,x<<1,s[x<<1]=='>'?1:0);27 if(((x<<1)|1)<=n) add(x,(x<<1)|1,s[(x<<1)|1]=='>'?1:0);28 for(int i=head[x];i>=0;i=e[i].nxt) {29 int to=e[i].to;dp(to);30 for(int j=sz[x];j>=1;j--) {31 for(int k=sz[to];k>=0;k--) {32 if(e[i].tp==1) t[x][j+k]=(t[x][j+k]+f[to][k]*C(j+k-1,k)%mod*C(sz[x]+sz[to]-j-k,sz[to]-k)%mod*f[x][j])%mod;33 else t[x][j+k]=(t[x][j+k]+g[to][k+1]*C(j+k-1,k)%mod*C(sz[x]+sz[to]-j-k,sz[to]-k)%mod*f[x][j])%mod;34 }35 }36 sz[x]+=sz[to];37 for(int j=0;j<=sz[x];j++) f[x][j]=t[x][j],t[x][j]=0;38 }39 for(int i=sz[x];i>=1;i--) g[x][i]=(g[x][i+1]+f[x][i])%mod;40 for(int i=1;i<=sz[x];i++) f[x][i]=(f[x][i]+f[x][i-1])%mod;41 }42 int main(){43 memset(head,-1,sizeof(head));44 n=read();45 scanf("%s",s+2);46 inv[0]=inv[1]=jc[0]=jc[1]=1;47 for(int i=2;i<=n;i++) jc[i]=jc[i-1]*i%mod,inv[i]=(mod-mod/i)*inv[mod%i]%mod;48 for(int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mod;49 dp(1);50 printf("%lld\n",f[1][sz[1]]);51 return 0;52 }
View Code

 

转载于:https://www.cnblogs.com/wls001/p/9818546.html

你可能感兴趣的文章
ASP.NET性能优化之构建自定义文件缓存
查看>>
Shell——windows上写完放入linux的时候需要注意的问题
查看>>
65条常用的正则表达式
查看>>
Vscode断点调试PHP
查看>>
做前端要做的6大事
查看>>
LeetCode 813. Largest Sum of Averages
查看>>
vSphere、Hyper-V与XenServer 你选哪个?
查看>>
java.lang.UnsupportedClassVersionError
查看>>
实现接口必须要加注解@Override吗
查看>>
apicloud UISearchBar 使用方法
查看>>
【spring+websocket的使用】
查看>>
mongo二维数组操作
查看>>
localStorage之本地储存
查看>>
Archlinux 交换左Ctrl和Cap键
查看>>
#openstack故障处理汇总
查看>>
搜索旋转排序数组 II
查看>>
20、docker swarm
查看>>
psp工具软件前景与范围文档
查看>>
day06-三元表达式
查看>>
C# DateTime.Now详细用法
查看>>