1. 程式人生 > >Codeforces Round #554 (Div. 2) D 貪心 + 記憶化搜索

Codeforces Round #554 (Div. 2) D 貪心 + 記憶化搜索

com problem ble 搜索 括號序列 long 記憶化 i++ 貪心

https://codeforces.com/contest/1152/problem/D

題意

給你一個n代表合法括號序列的長度一半,一顆有所有合法括號序列構成的字典樹上,選擇最大的邊集,邊集的邊沒有公共點,問邊集大小

題解

  • 對於一顆字典樹,從低向上貪心,最底層的邊全拿,定義好狀態,記憶化搜索計數
  • 定義dp[i][j]為左括號數量為i,右括號數量為j的最大邊集
    • \(i<n\),\(dp[i][j]->dfs(i+1,j)\)
    • \(j<i\),\(dp[i][j]->dfs(i,j+1)\)
  • 註意一下,相鄰兩層不能連續選邊

代碼

#include<bits/stdc++.h>
#define ll long long
#define P 1000000007
#define pii pair<ll,int>
#define mk make_pair
#define ft first
#define se second
using namespace std;
pii dp[1005][1005];
int n;

pii dfs(int i,int j){
    if(i==n&&j==n)return mk(0,0);
    pii &ans=dp[i][j];
    if(ans.ft>=0)return ans;
    ans=mk(0,1);
    if(i<n){
        pii tp=dfs(i+1,j);
        ans.ft+=tp.ft;ans.ft%=P;
        ans.se&=tp.se;
    }
    if(j<i){
        pii tp=dfs(i,j+1);
        ans.ft+=tp.ft;ans.ft%=P;
        ans.se&=tp.se;
    }
    if(ans.se==0){ans.ft++;ans.ft%=P;}
    ans.se^=1;
    return ans;
}
    
int main(){
    cin>>n;
    for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dp[i][j]=mk(-1,-1);
    cout<<dfs(1,0).ft;
}

Codeforces Round #554 (Div. 2) D 貪心 + 記憶化搜索