建议大家还是不要阅读此文了,因为我觉得这题我的解法实在是又不高效又不优美……只是想要记录一下,毕竟是除了中国象棋之外自己做出的组合dp第一题~

  首先如果做题做得多,比较熟练的话,应该能一眼看出这题所给的信息正好描述的是一棵二叉树上父子的大小关系。于是确立一个状态 \(f[u][i]\) 表示在 \(u\)  及 \(u\) 的子树内 \(u\) 排名第 i 名的总方案数。(这个状态应该还是比较好想,我当时想到这个状态觉得是可做的就坚持了这个状态)。那么就考虑如何通过 \(f[ch1][j], f[ch2][k]\) 即它的两个儿子来转移到当前的状态。

  我们可以注意到:由儿子转移到父亲,两个儿子之间其实是没有互相关联的,只要让它们都满足与父亲的大小限制即可。当排名为 \(j\) 的儿子小与父亲的时候,说明父亲前面起码预留出 \(j\) 个空位,而当排名为 \(j\) 的儿子大于父亲时,说明父亲的排名也不能超过限制使得后面不足 \(size2 - j + 1\) 个空位。设 \(S\) 为右儿子子树中排名 \( < i \) 的个数,则根据这个思路,就可以得出 \(S\) 的大小范围。

  于是我们有组合数转移方程 \(ans = f[ch1][j] * f[ch2][k] * C[i - 1][S] * C[size[u] - i][size[ch2] - S]\) ;

  代码又臭又长,不忍直视……

#include <bits/stdc++.h>
using namespace std;
#define maxn 400
#define int long long
#define mod 1000000007
int n, f[maxn][maxn], size[maxn];
int C[maxn][maxn], a[maxn]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void Get_C()
{
for(int i = ;i < maxn; i++)
C[i][] = , C[i][i] = ;
for(int i = ; i < maxn; i++)
for(int j = ; j < i; j++)
C[i][j] = (C[i - ][j - ] + C[i - ][j]) % mod;
} void DP(int u)
{
int ch1 = u * , ch2 = u * + ;
for(int i = ; i <= size[u]; i ++)
for(int j = ; j <= size[ch1]; j ++)
for(int k = ; k <= size[ch2]; k ++)
{
int tem = f[ch1][j] * f[ch2][k] % mod;
int l1 = size[ch1] - j + , l2 = size[ch2] - k + ;
if(a[ch1] && a[ch2])
{
if(i <= j + k) continue;
int minn = max(k, max(size[ch2] - (size[u] - i), i - size[ch1] - ));
int maxx = min(i - j - , size[ch2]);
for(int S = minn; S <= maxx; S ++)
{
int tt = tem * C[i - ][S] % mod * C[size[u] - i][size[ch2] - S] % mod;
f[u][i] = (f[u][i] + tt) % mod;
}
}
else if(a[ch1] || a[ch2])
{
int x = j, y = k, p = ch1, q = ch2;
if(a[ch2]) swap(j, k), swap(ch1, ch2);
int l1 = size[ch1] - j + , l2 = size[ch2] - k + ;
if(i <= j || i > size[u] - l2) { j = x, k = y, ch1 = p, ch2 = q; continue; }
int minn = max(i - - size[ch1], 0ll);
int maxx = min(i - - j, size[ch2] - l2);
for(int S = minn; S <= maxx; S ++)
{
int tt = tem * C[i - ][S] % mod * C[size[u] - i][size[ch2] - S] % mod;
f[u][i] = (f[u][i] + tt) % mod;
}
j = x, k = y, ch1 = p, ch2 = q;
}
else
{
int z = size[u] - i;
if(i > size[u] - l1 - l2) continue;
int minn = max(size[ch2] - (z - l1), 0ll);
int maxx = min(size[ch2] - l2, size[u] - z + l2 - );
for(int S = minn; S <= maxx; S ++)
{
int tt = tem * C[i - ][S] % mod * C[size[u] - i][size[ch2] - S] % mod;
f[u][i] = (f[u][i] + tt) % mod;
}
}
}
} void dfs(int u)
{
if(u > n) return;
dfs(u * ); dfs(u * + );
if(u * > n && u * + > n)
{
f[u][] = ; size[u] = ;
return;
}
int ch1 = u * , ch2 = u * + ;
size[u] = size[ch1] + size[ch2] + ;
if(ch2 <= n) DP(u);
else
{
for(int i = ; i <= size[u]; i ++)
for(int j = ; j <= size[ch1]; j ++)
{
if(a[ch1])
{
if(j >= i) continue;
f[u][i] = (f[u][i] + f[ch1][j]) % mod;
}
else
{
int p = size[ch1] - j + , z = size[u] - i;
if(z < p) continue;
f[u][i] = (f[u][i] + f[ch1][j]) % mod;
}
}
}
} signed main()
{
Get_C();
n = read();
for(int i = ; i <= n; i ++)
{
char c; cin >> c;
if(c == '>') a[i] = ;
}
dfs(); int ans = ;
for(int i = ; i <= n; i ++)
ans = (ans + f[][i]) % mod;
printf("%lld\n", ans);
return ;
}

【题解】CQOI2017老C的键盘的更多相关文章

  1. [CQOI2017]老C的键盘

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

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

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

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

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

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

    Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也 ...

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

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

  6. bzoj 4824: [Cqoi2017]老C的键盘

    Description 老 C 是个程序员.     作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 ...

  7. [bzoj4824][Cqoi2017]老C的键盘

    来自FallDream的博客,未经允许,请勿转载,谢谢. 老 C 是个程序员.     作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序在某种 ...

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

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

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

    [BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...

随机推荐

  1. linux下进程的最大线程数、进程最大数、进程打开的文件数

    linux下进程的最大线程数.进程最大数.进程打开的文件数   ===========最大线程数============== linux 系统中单个进程的最大线程数有其最大的限制 PTHREAD_TH ...

  2. Ubuntu 16.04 swoole扩展安装注意!!!

    前言:目前很多项目估计常常会用到swoole扩展,如个人使用Ubuntu虚拟机安装扩展,这里总结一下遇到的问题: 一.先保证服务器时间同步当前地区时间,如北京时间: 1.设定时区 如:设定时区:dpk ...

  3. Hadoop(11)-MapReduce概述和简单实操

    1.MapReduce的定义 2.MapReduce的优缺点 优点 缺点 3.MapReduce的核心思想 4.MapReduce进程 5.常用数据序列化类型 6.MapReduce的编程规范 用户编 ...

  4. Python3.X-文本编码问题

    1.请说明python2与python3的默认编码是什么? python的默认编码是ASCII码,python3的默认编码是utf-8 2.为什么会出现中文乱码?能列举出现乱码的情况有哪几种么? 编码 ...

  5. python 迭代器 和生成器

    迭代器 # 双下方法 # print([1].__add__([2])) # print([1]+[2]) # 迭代器 # l = [1,2,3] # 索引 # 循环 for # for i in l ...

  6. Go web表单

    package main import ( "fmt" "html/template" "log" "net/http" ...

  7. windows 安装 .net core 环境

    windows 安装 环境说明 window10系统 .net core 1.0.1 visual studio code 安装 .net core Windows系统下安装软件基本上属于傻瓜式安装, ...

  8. 最短路径算法 1.Floyed-Warshall算法

    这几周开始正式系统学习图论,新学期开始新的记录.由于二模和生物地理两门高考的临近,时间比较仓促,所以暂时跳过图论的(一)和(二),即图的储存和遍历.从最短路径算法学起,首先要学习的是Floyed-Wa ...

  9. 【Leetcode】709. To Lower Case

    To Lower Case Description Implement function ToLowerCase() that has a string parameter str, and retu ...

  10. ubuntu 关闭触控板

    第一种: 1 sudo rmmod psmouse    这个是禁用的 2 sudo modprobe psmouse 这个是启用的 这个方法很便捷,但是会将触点和触板都禁用了,一般还是希望保持触点是 ...