日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

B. Dispersed parentheses 记忆化搜索 + 括号序列的状压表示

發布時間:2023/12/13 综合教程 31 生活家
生活随笔 收集整理的這篇文章主要介紹了 B. Dispersed parentheses 记忆化搜索 + 括号序列的状压表示 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://codeforces.com/gym/100633/problem/B

B. Dispersed parentheses

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

The sequence of calculations in arithmetic expressions is usually set by a certain arrangement of parentheses. For example, (3·(2?+?1))·(4?-?5). After deleting all the elements from the expression except parentheses remaining symbols form a parentheses sequence (())(). Let’s assume that adding character ?0? does not corrupt the sequence. Let’s call such sequence a disperse parentheses sequence. Also this can be defined as follows:

An empty line is a disperse parentheses sequence.
If S and T— disperse parentheses sequences, then lines 0S,?S0,?(S) and ST are also disperse parentheses sequences.

The depth of disperse parentheses sequence is the maximum difference between the number of opening and closing parentheses in the sequence prefix. (The prefix of line S is the line, which can be obtained from S by deleting symbols from the tail of the line. For example, the prefixes of line ?ABCAB? are lines ??, ?A?, ?AB?, ?ABC?, ?ABCA? and ?ABCAB?.) Thus, the depth of the sequence ?(0)(0())0? equals two (prefix ?(0)(0(? contains three openinig and one closing parentheses).

Calculate the number of possible disperse parentheses sequences n symbols long, that have a depth k.

Input

Single line contains space-separated integers n and k (1?≤?n?≤?300, 0?≤?k?≤?n).

Output

Output the number of possible disperse parentheses sequences n symbols long, that have a depth k modulo (109?+?9).

Examples

Input

3 0

Output

1

Input

3 1

Output

3

Input

3 2

Output

0


這里學到了一個括號序列的狀壓表示,也就是,要表示一個合法的括號序列,除了用[lef][rig]表示有開括號lef個,
閉括號rig個之外,還可以用她們的差來表示,直接壓縮到一維,[dis]表示兩種括號的差值。可知當rig > lef的時候,整個序列是不可能合法的。所以dis < 0直接是0.
那么設dp[n + 1][dis][k]表示長度是n的括號序列,差值是dis,深度是k的合法情況。
ans = dp[n + 1][0][k]

那么可以按位dfs,開始的狀態是dis = 0, deep = 0, lef = 0, rig = 0,那么在第cur位,你可以放0,可以放'('或者')'。然后三種情況統計一次的和,就是第cur位的合法情況。

一開始從dp[1][0][0]出發,推導dp[n + 1][0][k]
dp[1][0][0]的意思是在第0位,差值是0,深度是k的合法情況數。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>

int n, k;
const int MOD = 1e9 + 9;
const int maxn = 300 + 20;
bool vis[maxn][maxn][maxn];
int dp[maxn][maxn][maxn];
int dfs(int cur, int dis, int deep, int lef, int rig) {
    if (dis < 0 || deep > k) return 0;
    if (vis[cur][dis][deep]) return dp[cur][dis][deep];
    vis[cur][dis][deep] = true;
    if (cur == n + 1) {
        if (dis == 0 && deep == k) {
            return dp[cur][dis][deep] = 1;
        } else return 0;
    }
    LL ans = 0;
    ans += dfs(cur + 1, dis, deep, lef, rig);
    ans += dfs(cur + 1, dis + 1, max(deep, lef + 1 - rig), lef + 1, rig);
    ans += dfs(cur + 1, dis - 1, max(deep, rig + 1 - lef), lef, rig + 1);
    return dp[cur][dis][deep] = ans % MOD;
}
void work() {
    scanf("%d%d", &n, &k);
    cout << dfs(1, 0, 0, 0, 0) << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}

View Code


如果不用這個括號序列的狀壓,則MLE。dp[n][deep][lef][rig]

2017年7月17日 20:40:26

現在來看這題。

其實是從第一位開始構造。

dp[i][j][k]

表示構造了i個,左括號和右括號差值是j,現在深度是k,在這個狀態下,后面那些序列隨便變,最后得到的合法情況數會是dp[i][j][k]

整個dfs的過程相當于在第cur位放什么的過程。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

const int MOD = 1e9 + 9;
LL dp[301][301][301];
bool vis[301][301][301];
int n, k;
LL dfs(int cur, int dis, int depth) {
    if (depth > k) return 0;
    if (cur == n + 1) {
        if (dis == 0 && depth == k) return 1;
        else return 0;
    }
    if (vis[cur][dis][depth]) return dp[cur][dis][depth];
    vis[cur][dis][depth] = true;
    LL ans1 = dfs(cur + 1, dis, depth);
    ans1 += dfs(cur + 1, dis + 1, max(dis + 1, depth));
    if (dis > 0) {
        ans1 += dfs(cur + 1, dis - 1, depth);
    }
    return dp[cur][dis][depth] = ans1 % MOD;
}
void work() {
    cin >> n >> k;
    cout << dfs(1, 0, 0) << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}

View Code





總結

以上是生活随笔為你收集整理的B. Dispersed parentheses 记忆化搜索 + 括号序列的状压表示的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。