合法括號序列(dp 組合數學)

2022-07-13 20:57:26 字數 1090 閱讀 6130

鍵盤上有左括號(,右括號),和退格鍵-,共三個鍵。

牛牛希望按鍵n次,使得輸入的字串恰好乙個合法的括號序列。

每按一次左括號(,字串末尾追加乙個左括號(

每按一次右括號),字串末尾追加乙個右括號)

每按一次退格鍵-,會刪掉字串的最後乙個字元,

特別的,如果字串為空,牛牛也可以按退格,但是什麼都不會發生。

輸出方案數對p取模,注意p可能不是質數。

注:只要按鍵方法不同,就是不同的方案,即使得到的序列一樣。

solution

這題和其他關於括號序列的題不太一樣,因為有了刪除操作。

由於我太zz,然後搞了個*b方程。

設dp[i][j]表示按了i次,造出了乙個長度為j的序列的方案數。

轉移是dp[i][j]=dp[i-1][max(0,j-1)]+dp[i-1][j+1]

這裡取max是指當序列為空時我也可以退格。

然後我們就有了乙個長度為j的序列,我們要把左括號和右括號往裡放,使得它是乙個合法的括號序列。

其實這個方案數就是卡特蘭數。

於是我們列舉長度,答案加上dp[n][i]*catalan(i/2)。

然後樣例**。

發現(+del和)+del最後製造出的序列是一樣的,但是是兩種不同的方案,但按照上面的方法dp只會計算一次。

所以刪除時要考慮刪什麼字元。

正確轉移方程:dp[i][j]=dp[i-1][max(0,j-1)]+dp[i-1][j+1]*2.

code

#include#include

#define n 1002

using

namespace

std;

typedef

long

long

ll;int

n;ll f[n][n],dp[n][n],p,ans;

intmain()

for(int i=0;i<=n;i+=2)(ans+=(f[i][0]*dp[n][i])%p)%=p;

printf(

"%lld\n

",ans);

return0;

}

組合數學 序列統計

題解 生成乙個長度為1 n的序列,在l,r區間中選擇數字。那麼有m r l 1個數字可以選擇,每個數字選擇的次數加起來為n,所以這是明顯的插空法。為了讓每個數字都一定會被選一次,所以左右全部 1,接下裡就是利用公式合併再盧卡斯一下了。pragma gcc optimize 2 include def...

合法括號序列

合法括號序列 鍵盤上有左括號 右括號 和退格鍵 共三個鍵。牛牛希望按鍵n次,使得輸入的字串恰好乙個合法的括號序列。每按一次左括號 字串末尾追加乙個左括號 每按一次右括號 字串末尾追加乙個右括號 每按一次退格鍵 會刪掉字串的最後乙個字元,特別的,如果字串為空,牛牛也可以按退格,但是什麼都不會發生。輸出...

組合數學 求組合數

對於求組合數,要根據所給資料範圍來選擇合適的演算法 這道題中所給的資料範圍適合用打表的方法直接暴力求解 先用4e6的複雜度預處理出所有的情況,再用1e4的複雜度完成詢問即可 include using namespace std const int n 2010 const int mod 1e9 ...