POJ 1187 陨石的秘密 (线性DP)
题意:
公元11380年,一颗巨大的陨石坠落在南极。于是,灾难降临了,地球上出现了一系列反常的现象。当人们焦急万分的时候,一支中国科学家组成的南极考察队赶到了出事地点。经过一番侦察,科学家们发现陨石上刻有若干行密文,每一行都包含5个整数:
1 1 1 1 6
0 0 6 3 57
8 0 11 3 2845
著名的科学家SS发现,这些密文实际上是一种复杂运算的结果。为了便于大家理解这种运算,他定义了一种SS表达式:
1. SS表达式是仅由'{','}','[',']','(',')'组成的字符串。
2. 一个空串是SS表达式。
3. 如果A是SS表达式,且A中不含字符'{','}','[',']',则(A)是SS表达式。
4. 如果A是SS表达式,且A中不含字符'{','}',则[A]是SS表达式。
5. 如果A是SS表达式,则{A}是SS表达式。
6. 如果A和B都是SS表达式,则AB也是SS表达式。
例如
()(())[]
{()[()]}
{{[[(())]]}}
都是SS表达式。
而
()([])()
[()
不是SS表达式。
一个SS表达式E的深度D(E)定义如下:
例如(){()}[]的深度为2。
密文中的复杂运算是这样进行的:
设密文中每行前4个数依次为L1,L2,L3,D,求出所有深度为D,含有L1对{},L2对[],L3对()的SS串的个数,并用这个数对当前的年份11380求余数,这个余数就是密文中每行的第5个数,我们称之为?神秘数?。
密文中某些行的第五个数已经模糊不清,而这些数字正是揭开陨石秘密的钥匙。现在科学家们聘请你来计算这个神秘数。
思路:
初始想法:我们令dp[l1][l2][l3][d]为用了l1个小括号,l2个中括号,l3个大括号,深度恰好为d时的方案数,现在我们来找状态之间的联系。然而我们可以发现一个残酷的事实,光用4个变量无法很好的表示一个状态。比如,我们添加一个小括号,当前状态带表的括号序列中,有一部分序列的深度增加了,有一部分没有增加,所以为了正确的转移状态,正常想法就是用状压之类的记录具体方案,然而这个题就。。。
我们可以发现,新添加一个括号,括号序列的深度最多增加1,要么就不变,所以,如果dp[l1][l2][l3][d]表示的是用了l1个小括号,l2个中括号,l3个大括号,深度小于等于d的方案数就很好办了,添加一个括号后从深度小于等于d的状态转移到深度小于等于d + 1的状态。
则等于d的方案数 = 小于等于d的方案数 - 小于等于d - 1的方案数。
还有一个问题,我们怎么不重不漏的写出状态转移的过程?我们可以发现,所有深度小于等于d的括号序列是由若干个深度小于等于d的嵌套的括号构成的,所以,我们可以这样转移状态:我们把当前状态分成2个部分,一个部分用来形成嵌套的括号,另一部分对应的是那个状态的方案数。我们枚举向最里面添加什么括号。因为大括号外面不能有其它的括号,所以当在最里面套大括号时,只能有大括号。例如,当前嵌套形的括号是{[()]},我们不能向里面添加{},但是添加小括号可以,变成{[(())]}。同理,枚举状态时,当添加的是中括号时,外面只能是中括号和大括号。
思路和代码实现参考了这篇博客:https://blog.csdn.net/Flying_Stones_Sure/article/details/7954114
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int mod = 11380;
int dp[11][11][11][31];
bool v[11][11][11][31];
int dfs(int l1, int l2, int l3, int deep) {
if (l1 == 0 && l2 == 0 && l3 == 0) {
v[l1][l2][l3][deep] = 1;
return dp[l1][l2][l3][deep] = 1;
}
if (deep == 0) {
v[l1][l2][l3][deep] = 1;
return dp[l1][l2][l3][deep] = 0;
}
if (v[l1][l2][l3][deep])
return dp[l1][l2][l3][deep];
int ans = 0;
for (int i = 0; i <= l3; i++) {
if (i) {
ans = (ans + dfs(0 , 0, i - 1, deep - 1) * dfs(l1, l2, l3 - i, deep)) % mod;
}
for (int j = 0 ;j <= l2; j++) {
if (j) {
ans = (ans + dfs(0, j - 1, i, deep - 1) * dfs(l1, l2 - j, l3 - i, deep)) % mod;
}
for (int k = 1; k <= l1; k++) {
ans = (ans + dfs(k - 1, j, i, deep - 1) * dfs(l1 - k, l2 - j, l3 - i, deep)) % mod;
}
}
}
v[l1][l2][l3][deep] = 1;
return dp[l1][l2][l3][deep] = ans;
}
int main() {
int n, m, d, t;
while(~scanf("%d%d%d%d", &n, &m, &t, &d)) {
dfs(n, m, t, d);
if(d) dfs(n, m ,t, d - 1);
if(d) {
printf("%d\n", (dp[n][m][t][d] - dp[n][m][t][d - 1] + mod ) % mod);
} else {
printf("%d\n", dp[n][m][t][d]);
}
}
}
POJ 1187 陨石的秘密 (线性DP)的更多相关文章
- poj 1050 To the Max(线性dp)
题目链接:http://poj.org/problem?id=1050 思路分析: 该题目为经典的最大子矩阵和问题,属于线性dp问题:最大子矩阵为最大连续子段和的推广情况,最大连续子段和为一维问题,而 ...
- POJ 2479-Maximum sum(线性dp)
Maximum sum Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33918 Accepted: 10504 Des ...
- LightOJ1044 Palindrome Partitioning(区间DP+线性DP)
问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...
- Codeforces 176B (线性DP+字符串)
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...
- hdu1712 线性dp
//Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...
- Genotype&&陨石的秘密
Genotype: Genotype 是一个有限的基因序列.它是由大写的英文字母A-Z组成,不同的字母表示不同种类的基因.一个基因可以分化成为一对新的基因.这种分化被一个定义的规则集合所控制.每个分化 ...
- 动态规划——线性dp
我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...
- nyoj44 子串和 线性DP
线性DP经典题. dp[i]表示以i为结尾最大连续和,状态转移方程dp[i] = max (a[i] , dp[i - 1] + a[i]) AC代码: #include<cstdio> ...
- 『最大M子段和 线性DP』
最大M子段和(51nod 1052) Description N个整数组成的序列a[1],a[2],a[3],-,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M &g ...
随机推荐
- C# 6.0 编译器
C# 6.0编译器:可以将csc.exe所在位置 C:\Program Files (x86)\MSBuild\14.0\Bin 添加到Path环境变量. C:\>csc Microsoft ( ...
- uva10648 概率dp
https://vjudge.net/problem/UVA-10648 将n个不同小球放入m个不同盒子,放入每个盒子的概率相同,问放完之后仍有空盒子的概率: 还是太傻- -,可以倒着计算出放完之后没 ...
- oracle管理优化必备语句以及oracle SQL语句性能调整
本文转自http://www.dataguru.cn/article-3302-1.html oracle数据库管理优化必备语句: 1. SELECT T.START_TIME,T.USED_UBLK ...
- vue 全选与取消全选
所用知识点 1 v-model:监听input内容 2 watch:监听属性方法 参考https://cn.vuejs.org/v2/api/#watch 3 页面初始化调用函数 mounted 一: ...
- Git_学习_07_ 推送修改到远端
一.操作流程 多人协作时,若自己的本地代码有了修改,想提交自己的代码,就需要按照以下步骤操作: 1.确认修改正确 使用以下命令,查看有哪些是自己未提交的代码 git status 2.拉取远程最新代码 ...
- nyoj-155-求高精度幂(java大数)
题目链接 import java.util.*; import java.math.*; public class Main{ public static void main(String[] arg ...
- hdu--1878--欧拉回路(并查集判断连通,欧拉回路模板题)
题目链接 /* 模板题-------判断欧拉回路 欧拉路径,无向图 1判断是否为连通图, 2判断奇点的个数为0 */ #include <iostream> #include <c ...
- /dev/root: No such file or directory
/*************************************************************************** * /dev/root: No such fi ...
- ENTRYPOINT 与 CMD
在Dockerfile中 ENTRYPOINT 只有最后一条生效,如果写了10条,前边九条都不生效 ENTRYPOINT 的定义为运行一个Docker容器像运行一个程序一样,就是一个执行的命令 两种写 ...
- Redis底层探秘(四):整数集合及压缩列表
整数集合 整数集合(intset)是集合键的底层实现之一,当一个集合只包含 整数值元素,并且这个集合的元素数量不多时,Redis就会使用郑书记和作为集合键的底层实现. 整数集合的实现 整数集合是red ...