其他分享
首页 > 其他分享> > "蔚来杯"2022牛客暑期多校训练营2 K/L补题

"蔚来杯"2022牛客暑期多校训练营2 K/L补题

作者:互联网

"蔚来杯"2022牛客暑期多校训练营2

题目大意:给定一个长度为\(n\)的括号序列\(a\),\(a\)是一个长度为\(m\)的合法括号序列\(b\)的子序列,求\(b\)的方案数

(\(mod\ 10^9+7,1 \le n \le m \le 200\) )

解题思路:考虑类似最长公共子序列的动态规划,加上括号序列需要合法的限制

定义状态:

\[dp[i][j][k]:=b的前i个最多匹配a的前j个,剩下k个左括号未匹配的方案数 \]

状态转移:

\(b\)多放一个左括号

\[a_{j+1}==')'\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j][k+1]\\ a_{j+1}=='('\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j+1][k+1] \]

\(b\)多放一个右括号

\[a_{j+1}=='('\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j][k-1]\\ a_{j+1}==')'\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j+1][k-1] \]

AC代码:

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

#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)

const int N = 210, MOD = 1e9 + 7;

int dp[N][N][N];
char a[N];

void work() {
	int n,m;
	cin>>n>>m>>a+1;
	
	memset(dp,0,sizeof dp);
	dp[0][0][0]=1;
	
	rep(i,0,m-1){
		rep(j,0,min(i,n)){
			rep(k,0,i){
				// '('
			    if(a[j+1]=='(') dp[i+1][j+1][k+1]=(dp[i+1][j+1][k+1]+dp[i][j][k])%MOD;	
				else dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k])%MOD; 	 		 
				// ')'
				if(!k) continue;
				if(a[j+1]==')') dp[i+1][j+1][k-1]=(dp[i+1][j+1][k-1]+dp[i][j][k])%MOD;
				else dp[i+1][j][k-1]=(dp[i+1][j][k-1]+dp[i][j][k])%MOD;
			}
		}
	}
	
	cout<<dp[m][n][0]<<endl;
}

signed main() {
	int test=1;
	cin >> test;
	
	while (test--) 
		work();
	
	return 0;
}

题目大意:有\(n\)个世界,每个世界是一个\(m\)个点的无向图。选择一个世界从其编号为\(1\)的起点出发,每个世界可以不动或者走一条边到达下一个点\(u\),然后跳到下一个世界的点\(u\),如果跳到点\(m\)则胜利。求一个可以获胜的最短连续子段。

(\(1<=n<=10^4,2<=m<=2*10^3 ,ML=32MB\))

解题思路:考虑\(bfs\)或者\(dp\)或者乱搞,这里给出\(dp\)的做法。因为有空间限制,\(dp\)需要用滚动数组优化。

定义状态:

\[dp[i][j]:=最大的k,可以从第k个世界编号为1的点到达第i个世界编号为j的点 \]

状态转移:

\[dp[i+1][1]=i+1\\dp[i+1][v]=_{max_{u\longrightarrow\ v}}\ dp[i][u] \]

AC代码:

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

#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 2e5 + 10;

int dp[2][N];

void work() {
	memset(dp,-1,sizeof dp);
	int n,m;
	cin>>n>>m;
	
	int ans=INF;
	rep(i,1,n){
		dp[0][1]=i;
		
		int k;
		cin>>k;
		while(k--){
			int a,b;
			cin>>a>>b;
			dp[1][b]=max(dp[1][b],dp[0][a]);
		}
		
		if(dp[1][m]!=-1) ans=min(ans,i-dp[1][m]+1);
		rep(j,1,m) dp[0][j]=dp[1][j];
	}
	
	if(ans==INF) cout<<-1<<endl;
	else cout<<ans<<endl;	
}

signed main() {
	IO
	int test=1;
	
	while (test--) 
		work();
    
	return 0;
}

标签:int,蔚来,rep,多校,括号,补题,Longrightarrow,longrightarrow,dp
来源: https://www.cnblogs.com/xhy666/p/16525890.html