Codeforces 1152 D Neko and Aki's Prank 题解(记忆化搜索)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/89603324

题目:CF1152D
题目大意:将所有长度为 2 n 2n 的括号序列(对于每个位置前面的左括号数量必须大于右括号数量)插入一个Trie中,然后给选出这棵Trie中的一个边集使得这些边没有交点,使得边集大小最大.
1 n 1 0 3 1\leq n\leq 10^3 .

我们可以考虑大力dfs构造出这棵Trie并在这棵Trie上DP统计,但是这个算法的复杂度是指数级的,根本无法接受.

容易发现若两个子Trie的根到大Trie的根这一条链上已用左括号和右括号数量相同时,两个子Trie一定是相同的,两个相同的子Trie是不是不需要重复计算了呢?

那么我们就可以设 d p [ l ] [ r ] [ 0 / 1 ] dp[l][r][0/1] 表示已用左括号 l l 个右括号 r r 个时,根被选/不被选时的方案数,这样子就可以做到 O ( n 2 ) O(n^2) 解决这个问题了,具体实现可以用记忆化搜索.

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=1000,mod=1000000007;

int n,dp[N+9][N+9][2],vis[N+9][N+9][2];

int dfs(int l,int r,int k){
  if (vis[l][r][k]) return dp[l][r][k];
  vis[l][r][k]=1;
  int ans=0,t=k;
  if (l<n){
  	ans=(ans+dfs(l+1,r,t^1)+(t^1))%mod;
  	t=1;
  }
  if (l>r) ans=(ans+dfs(l,r+1,t^1)+(t^1))%mod;
  return dp[l][r][k]=ans;
}

Abigail into(){
  scanf("%d",&n);
}

Abigail outo(){
  printf("%d\n",(1+dfs(1,0,1))%mod);
}

int main(){
  into();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/89603324