版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/89603324
题目:CF1152D
题目大意:将所有长度为
的括号序列(对于每个位置前面的左括号数量必须大于右括号数量)插入一个Trie中,然后给选出这棵Trie中的一个边集使得这些边没有交点,使得边集大小最大.
.
我们可以考虑大力dfs构造出这棵Trie并在这棵Trie上DP统计,但是这个算法的复杂度是指数级的,根本无法接受.
容易发现若两个子Trie的根到大Trie的根这一条链上已用左括号和右括号数量相同时,两个子Trie一定是相同的,两个相同的子Trie是不是不需要重复计算了呢?
那么我们就可以设 表示已用左括号 个右括号 个时,根被选/不被选时的方案数,这样子就可以做到 解决这个问题了,具体实现可以用记忆化搜索.
代码如下:
#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;
}