POJ 1187 陨石的秘密 (线性DP)
題意:
公元11380年,一顆巨大的隕石墜落在南極。于是,災(zāi)難降臨了,地球上出現(xiàn)了一系列反常的現(xiàn)象。當(dāng)人們焦急萬分的時(shí)候,一支中國科學(xué)家組成的南極考察隊(duì)趕到了出事地點(diǎn)。經(jīng)過一番偵察,科學(xué)家們發(fā)現(xiàn)隕石上刻有若干行密文,每一行都包含5個(gè)整數(shù):?
1 1 1 1 6?
0 0 6 3 57?
8 0 11 3 2845?
著名的科學(xué)家SS發(fā)現(xiàn),這些密文實(shí)際上是一種復(fù)雜運(yùn)算的結(jié)果。為了便于大家理解這種運(yùn)算,他定義了一種SS表達(dá)式:?
1. SS表達(dá)式是僅由'{','}','[',']','(',')'組成的字符串。?
2. 一個(gè)空串是SS表達(dá)式。?
3. 如果A是SS表達(dá)式,且A中不含字符'{','}','[',']',則(A)是SS表達(dá)式。?
4. 如果A是SS表達(dá)式,且A中不含字符'{','}',則[A]是SS表達(dá)式。?
5. 如果A是SS表達(dá)式,則{A}是SS表達(dá)式。?
6. 如果A和B都是SS表達(dá)式,則AB也是SS表達(dá)式。?
例如?
()(())[]?
{()[()]}?
{{[[(())]]}}?
都是SS表達(dá)式。?
而?
()([])()?
[()?
不是SS表達(dá)式。?
一個(gè)SS表達(dá)式E的深度D(E)定義如下:?
?
例如(){()}[]的深度為2。?
密文中的復(fù)雜運(yùn)算是這樣進(jìn)行的:?
設(shè)密文中每行前4個(gè)數(shù)依次為L1,L2,L3,D,求出所有深度為D,含有L1對(duì){},L2對(duì)[],L3對(duì)()的SS串的個(gè)數(shù),并用這個(gè)數(shù)對(duì)當(dāng)前的年份11380求余數(shù),這個(gè)余數(shù)就是密文中每行的第5個(gè)數(shù),我們稱之為?神秘?cái)?shù)?。?
密文中某些行的第五個(gè)數(shù)已經(jīng)模糊不清,而這些數(shù)字正是揭開隕石秘密的鑰匙。現(xiàn)在科學(xué)家們聘請(qǐng)你來計(jì)算這個(gè)神秘?cái)?shù)。?
思路:
初始想法:我們令dp[l1][l2][l3][d]為用了l1個(gè)小括號(hào),l2個(gè)中括號(hào),l3個(gè)大括號(hào),深度恰好為d時(shí)的方案數(shù),現(xiàn)在我們來找狀態(tài)之間的聯(lián)系。然而我們可以發(fā)現(xiàn)一個(gè)殘酷的事實(shí),光用4個(gè)變量無法很好的表示一個(gè)狀態(tài)。比如,我們添加一個(gè)小括號(hào),當(dāng)前狀態(tài)帶表的括號(hào)序列中,有一部分序列的深度增加了,有一部分沒有增加,所以為了正確的轉(zhuǎn)移狀態(tài),正常想法就是用狀壓之類的記錄具體方案,然而這個(gè)題就。。。
我們可以發(fā)現(xiàn),新添加一個(gè)括號(hào),括號(hào)序列的深度最多增加1,要么就不變,所以,如果dp[l1][l2][l3][d]表示的是用了l1個(gè)小括號(hào),l2個(gè)中括號(hào),l3個(gè)大括號(hào),深度小于等于d的方案數(shù)就很好辦了,添加一個(gè)括號(hào)后從深度小于等于d的狀態(tài)轉(zhuǎn)移到深度小于等于d + 1的狀態(tài)。
則等于d的方案數(shù) = 小于等于d的方案數(shù) - 小于等于d - 1的方案數(shù)。
還有一個(gè)問題,我們怎么不重不漏的寫出狀態(tài)轉(zhuǎn)移的過程?我們可以發(fā)現(xiàn),所有深度小于等于d的括號(hào)序列是由若干個(gè)深度小于等于d的嵌套的括號(hào)構(gòu)成的,所以,我們可以這樣轉(zhuǎn)移狀態(tài):我們把當(dāng)前狀態(tài)分成2個(gè)部分,一個(gè)部分用來形成嵌套的括號(hào),另一部分對(duì)應(yīng)的是那個(gè)狀態(tài)的方案數(shù)。我們枚舉向最里面添加什么括號(hào)。因?yàn)榇罄ㄌ?hào)外面不能有其它的括號(hào),所以當(dāng)在最里面套大括號(hào)時(shí),只能有大括號(hào)。例如,當(dāng)前嵌套形的括號(hào)是{[()]},我們不能向里面添加{},但是添加小括號(hào)可以,變成{[(())]}。同理,枚舉狀態(tài)時(shí),當(dāng)添加的是中括號(hào)時(shí),外面只能是中括號(hào)和大括號(hào)。
思路和代碼實(shí)現(xiàn)參考了這篇博客: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]);}} }
轉(zhuǎn)載于:https://www.cnblogs.com/pkgunboat/p/10339523.html
總結(jié)
以上是生活随笔為你收集整理的POJ 1187 陨石的秘密 (线性DP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [php] 高级教程
- 下一篇: 南阳师范学院ACM集训队博客使用方法