Luogu P3757 [CQOI2017]老C的键盘

题目描述

老C的键盘

题解

显然对于每个数 x 都有唯一对应的 \(x/2\) , 然而对于每个数 x 却可以成为 \(x*2\) 和 \(x*2+1\) 的对应数
根据这一特性想到了啥??? 感谢leo101的友情点拨

二叉树!!!

所以可以把 x/2 看做是 x的父亲, 1 显然就是根
可以把 < 看作是由父亲连向儿子的有向边, > 看作是儿子连向父亲的有向边
所以就是求这棵树的拓扑序的方案数就好了!!!
考虑当前节点的两棵子树都已处理完的时候
在满足和 当前节点的关系的同时, 两颗子树在拓扑序中出现的顺序显然是没有影响的,所以按照子树大小组合数乱搞就好了
然后设 dp[i][j] 表示 i 号节点在当前子树排在第 j 位的方案数就好了

代码


#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define in inline
#define get getchar()
in int read()
{
    int t=0; char ch=get;
    while (ch<'0' || ch>'9') ch=get;
    while (ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    return t;
}
const int mod=1e9+7;
const int _=1010;
ll n,dp[_][_],c[_][_],siz[_]; //siz[i]是以i为根的子树节点个数, c[][]是组合数
char s[_];
in void dfs(ll x)
{
    for(re int to=2*x;to<=min(n,2*x+1);to++)
    {
        dfs(to);
        if(s[to]=='>')
        {
            for(re ll k=siz[x]+siz[to]; k>=1; k--)
            {
                ll sum=0;
                for( re int i=1; i<=min(siz[x],k); i++)
                {
                    for (re int j=k-i+1;j<=siz[to];j++)
                    {
                        ll a=(dp[x][i]*dp[to][j])%mod;
                        ll b=(c[i-1][k-1]*c[siz[x]-i][siz[x]+siz[to]-k])%mod;
                        a=(a*b)%mod;
                        sum=(sum+a)%mod;
                    }
                }
                dp[x][k]=sum;
            }
        }
        else
        {
            for(re ll k=siz[x]+siz[to]; k>=1; k--)
            {
                ll sum=0;
                for(re int i=1; i<=min(siz[x],k); i++)
                    for(re int j=1; j<=min(k-i,siz[to]); j++)
                    {
                        ll a=(dp[x][i]*dp[to][j])%mod;
                        ll b=(c[i-1][k-1]*c[siz[x]-i][siz[x]+siz[to]-k])%mod;
                        a=(a*b)%mod;
                        sum=(sum+a)%mod;
                    }
                dp[x][k]=sum;
            }
        }
        siz[x]+=siz[to]; //子树大小统计
    }
}
int main()
{
    n=read();
    scanf("%s",s+2);
    c[0][0]=1;
    for (re int i=1; i<=n; i++)
    {
        c[0][i]=1,c[i][i]=1;
        dp[i][1]=1,siz[i]=1;
        for (re int j=1; j<i; j++) c[j][i]=(c[j][i-1]+c[j-1][i-1])%mod;
    } //预处理组合数
    dfs(1);
    ll ans=0;
    for (re int i=1; i<=n; i++) ans=(ans+dp[1][i])%mod; //因为一号节点是整棵树的根
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/yzhx/p/10643461.html

时间: 2024-10-11 20:43:55

Luogu P3757 [CQOI2017]老C的键盘的相关文章

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

Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也是一个程序员.有一天他悄悄潜入了老 C 的家中,想要看看这个 键盘究竟有何妙处.他发现,这个键盘共有n个按键,这n个按键虽然整齐的排成一列,但是每个键的高度却互不相同 .聪明的小 Q 马上将每个键的高度用 1 ~ n 的整数表示了出来,得到一个 1 ~ n 的排列 h1, h2,..., hn .为

[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]\)表示颜色

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个限制的情况下,任何两个关卡都存在某种程度的关联性.即,我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集

bzoj4822: [Cqoi2017]老C的任务

4822: [Cqoi2017]老C的任务 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 284  Solved: 152[Submit][Status][Discuss] Description 老 C 是个程序员. 最近老 C 从老板那里接到了一个任务--给城市中的手机基站写个管理系统.作为经验丰富的程序员,老 C 轻松 地完成了系统的大部分功能,并把其中一个功能交给你来实现.由于一个基站的面积相对于整个城市面积来说非常 的小,因此每个的基站

bzoj4823: [Cqoi2017]老C的方块(最小割)

4823: [Cqoi2017]老C的方块 题目:传送门 题解: 毒瘤题ORZ.... 太菜了看出来是最小割啥边都不会建...狂%大佬强强强   黑白染色?不!是四个色一起染,四层图跑最小割... 很惊奇的发现染完色之后只要是不喜欢的图形都一定可以由黄-->黑-->红-->绿 组成 那就很nice啦...兴高采烈的去敲代码...结果10^5*10^5???搞毛线...太弱了ORZ,又看了一波大佬的操作,用map存! woc...不谈了不谈了...撸撸撸(分情况分到想屎...虽然不多) 注

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

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

bzoj4822: [Cqoi2017]老C的任务(扫描线+BIT/线段树)

裸题... 依旧是写了BIT和线段树两种(才不是写完线段树后才想起来可以写BIT呢 怎么卡常数都挺大...QAQ ccz和yy的写法好快哇 BIT: #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<map> #define ll long