【题解】CQOI2017老C的键盘
建议大家还是不要阅读此文了,因为我觉得这题我的解法实在是又不高效又不优美……只是想要记录一下,毕竟是除了中国象棋之外自己做出的组合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的键盘的更多相关文章
- [CQOI2017]老C的键盘
[CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ ...
- [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数
4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 218 Solved: 171[Submit][Statu ...
- [BZOJ4824][CQOI2017]老C的键盘(树形DP)
4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 193 Solved: 149[Submit][Statu ...
- [bzoj4824][洛谷P3757][Cqoi2017]老C的键盘
Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也 ...
- Luogu P3757 [CQOI2017]老C的键盘
题目描述 老C的键盘 题解 显然对于每个数 x 都有唯一对应的 \(x/2\) , 然而对于每个数 x 却可以成为 \(x*2\) 和 \(x*2+1\) 的对应数 根据这一特性想到了啥??? 感谢l ...
- bzoj 4824: [Cqoi2017]老C的键盘
Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 ...
- [bzoj4824][Cqoi2017]老C的键盘
来自FallDream的博客,未经允许,请勿转载,谢谢. 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序在某种 ...
- 洛谷 P3757 [CQOI2017]老C的键盘
题面 luogu 题解 其实就是一颗二叉树 我们假设左儿子小于根,右儿子大于根 考虑树形\(dp\) \(f[u][i]\)表示以\(u\)为根的子树,\(u\)为第\(i\)小 那么考虑子树合并 其 ...
- 【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘
[BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...
随机推荐
- Java : java基础(2) 集合&正则&异常&File类
Obj 方法: hashCode() 返回内存地址值, getClass() 返回的时运行时类, getName() 返回类名, toString() 把名字和hashCode() 合在一起返回,如果 ...
- php-语言参考-类型3.2-未完待续
一,PHP变量的8个类型 四种标量类型: boolean (布尔型) integer (整型) float (浮点型, 也称作 double) string (字符串) 两种复合类型: array ( ...
- ruby mysql2
1. mysql2连接选项 Mysql2::Client.new( :host, :username, :password, :port, :database, :socket = '/path/to ...
- Leecode刷题之旅-C语言/python-70爬楼梯
/* * @lc app=leetcode.cn id=70 lang=c * * [70] 爬楼梯 * * https://leetcode-cn.com/problems/climbing-sta ...
- ABAP CDS ON HANA-(7)CDSビューでの集約
Aggregate expression in CDS View An aggregate expression calculates a single value from an operand o ...
- 如何在WIN7_64环境下安装Oracle10g_64位版本
转载请注明出处http://www.cnblogs.com/SharpL/p/4338638.html 1.如果之前安装过Oracle软件,建议完全卸载(究竟有没有必要_不知道_我是这么做的) 2.清 ...
- DDL失败案例
问题描述 今天对线上某个业务的大表120G进行重建表操作时遇到报错,该表有个比较显著的特征是*写入量比较大,每天写入加更新的频率在数千万级别.大致的环境 1 版本:Percona 5.6.24 2 操 ...
- 北京Uber优步司机奖励政策(3月25日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 【Consul】多数据中心
Consul的一个关键特性是支持多数据中心.consul架构中提到是构建低耦合的多个数据中心,一个数据中心的网络连接问题或故障不在其他数据中心的可用性.每个数据中心都是独立运行,并且拥有私有的LAN ...
- linux的常用易忘命令
1.查看软件安装路径 [root@localhost ~]# which gcc /usr/bin/gcc 查询进程 ps -ef |grep redis 查看端口 netstat -lntp |g ...