建议大家还是不要阅读此文了,因为我觉得这题我的解法实在是又不高效又不优美……只是想要记录一下,毕竟是除了中国象棋之外自己做出的组合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. angularjs1+requirejs+ bootstrap+ jQuery低版本配合兼容ie8+浏览器

    angularjs兼容低版本IE浏览器(IE8)angularjs在1.3之后的版本都是选择放弃对IE8及更低IE版本的支持,但是就目前的开发形式来看,IE8的使用客户还是蛮多的,最近有个项目要求尽量 ...

  2. ERROR: bootstrap checks failed

    错误描述:Linux默认配置的参数过小,需要自己设置 max file descriptors [4096] for elasticsearch process is too low, increas ...

  3. Hadoop(14)-MapReduce框架原理-切片机制

    1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...

  4. java中方法的参数传递机制_一个对象被当作参数传递到一个方法后

    一个例子: 在Boy.java类中 在Girl.java类中      在marry方法中的this指的是这个方法所属的对象的引用,在这里指的是girl这个对象 在BoyGirlTest.java测试 ...

  5. Pig关系型运算符例子

    1.新建两个文件A.txt与B.txt, A.txt文件的内容如下: 0,1,2 1,3,4 B.txt文件的内容如下: 0,5,2 1,7,8 将这两个文件上传到目录/zwy/soft 2.定义关系 ...

  6. Python学习:1.快速搭建python环境

    一.安装python 现在python有两个比较大的版本一个是python3.x一个是python2.x,python3.x相当于与python2.x是一个比较大的升级,但是python3.x没有向下 ...

  7. FPGA算法学习(1) -- Cordic(圆周系统之旋转模式)

    三角函数的计算是个复杂的主题,有计算机之前,人们通常通过查找三角函数表来计算任意角度的三角函数的值.这种表格在人们刚刚产生三角函数的概念的时候就已经有了,它们通常是通过从已知值(比如sin(π/2)= ...

  8. 为什么我要放弃javaScript数据结构与算法(第三章)—— 栈

    有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第三章 栈 栈数据结构 栈是一种遵循后进先出(LIFO)原则的有序集合.新添加的或待删除的元素都保存在栈的同一端,称为栈顶,另一 ...

  9. JAVA大作业汇总3

    JAVA大作业3 代码 ``` package thegreatwork; import java.util.; import java.io.; /Board.java 目的:里面有一些关于如何移动 ...

  10. 从一个线上服务器警告谈谈backlog

    缘起 双十一如期而至,此时的我因为在处理客户的一个问题已经陷入了忙碌.突然,不断接到驻场实施发来的反馈,都是相同的反馈--"客户端操作缓慢". 我现在负责的服务器是一台接口服务器, ...