Codeforces Round #604 Div2

本文深入解析了算法竞赛中两种常见问题的解决方案,包括构造贪心策略解决数字序列构造问题,以及使用区间动态规划解决括号序列深度求和问题,提供了详细的代码实现与复杂度分析。

1265D Beautiful Sequence(构造 贪心)

题意:

​ 给你若干数量的0、1、2、3,用完所有的数字构造一个序列使得任意相邻两数相差恰好为1。

解法:

​ 首先确定0和2的相对位置如下:0,0,0,……,0,0,2,2,……,2,2。此时1可放在任意两数之间,3只能放在两个2之间或放在最右侧,故只要最大化可以放3的放置,剩余位放1即可。

​ 于是有以下的贪心策略:以最小或次小的数作为首项,设前一位放置数字x,若x-1的数量不为0就放置x-1,否则放置x+1,若x+1的数量为0则无解。

​ 复杂度: O ( n ) O(n) O(n)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int ans[maxn],a[5],tmp[5];
bool check(int fst,int n)
{
	int pt=fst;
	for(int i=0;i<4;i++)
		tmp[i]=a[i];
	if(!tmp[fst]) return false;
	for(int i=1;i<=n;i++)
	{
		ans[i]=pt,tmp[pt]--;
		if(i==n) break;
		if(pt&&tmp[pt-1]) pt--;
		else if(tmp[pt+1]) pt++;
		else return false;
	}
	return true;
}
int main()
{
	int n=0;
	for(int i=0;i<4;i++)
		scanf("%d",&a[i]),n+=a[i];
	for(int i=0;i<4;i++) if(check(i,n))
	{
		puts("YES");
		for(int j=1;j<=n;j++)
			printf("%d ",ans[j]);
		return 0;
	}
	puts("NO");
}

1265F Beautiful Bracket Sequence (ev)(区间DP)

题意:

​ 给一个仅由’?’、’(’、’)‘组成的字符串S,其中每一个’?‘均可被替换为’(’、’)’,求所有可能的全部’?'被替换后形成的字符串的括号嵌套深度之和,替换后形成的字符串不一定是合法的括号序列 ( ∣ S ∣ ≤ 2000 ) (|S|\le2000) (S2000)

解法:

​ 考虑区间DP,设 d p [ l ] [ r ] dp[l][r] dp[l][r]为串 S l , S l + 1 , . . . , S r − 1 , S r S_l,S_{l+1},...,S_{r-1},S_r Sl,Sl+1,...,Sr1,Sr替换后形成的所有串的括号嵌套深度之和。现求 d p [ l ] [ r ] dp[l][r] dp[l][r]的值,对 S l S_l Sl S r S_r Sr进行讨论,有如下的转移方程:

  1. S l = = ′ ) ′ S_l==')' Sl==),则 S l S_l Sl一定不对答案产生贡献: d p [ l ] [ r ] = d p [ l + 1 ] [ r ] dp[l][r]=dp[l+1][r] dp[l][r]=dp[l+1][r]
  2. S r = = ′ ( ′ S_r=='(' Sr==(,同理有: d p [ l ] [ r ] = d p [ l ] [ r − 1 ] dp[l][r]=dp[l][r-1] dp[l][r]=dp[l][r1]
  3. S l = = ′ ( ′ S_l=='(' Sl==( S r = = ′ ) ′ S_r==')' Sr==),我们已知 d p [ l + 1 ] [ r − 1 ] dp[l+1][r-1] dp[l+1][r1],仅需考虑 S l S_l Sl S r S_r Sr两端对答案的贡献。设 T = S l + 1 , S l + 2 , . . . , S r − 2 , S r − 1 T=S_{l+1},S_{l+2},...,S_{r-2},S_{r-1} T=Sl+1,Sl+2,...,Sr2,Sr1,k为T中’?‘的数量,则当T中所有的’?'被替换后将形成 2 k 2^k 2k种不同的串,故 S l S_l Sl S r S_r Sr的贡献为 2 k 2^k 2k d p [ l ] [ r ] = d p [ l + 1 ] [ r − 1 ] + 2 k dp[l][r]=dp[l+1][r-1]+2^k dp[l][r]=dp[l+1][r1]+2k
  4. S l = = ′ ? ′ S_l=='?' Sl==? S r = = ′ ) ′ S_r==')' Sr==) S l S_l Sl能被替换为’(‘或’)’,故产生两种新串。当 S l = = ′ ) ′ S_l==')' Sl==)时,整个串对答案的贡献同1. ,为 d p [ l + 1 ] [ r ] dp[l+1][r] dp[l+1][r];当 S l = = ′ ( ′ S_l=='(' Sl==(时,整个串对答案的贡献同3. ,为 d p [ l + 1 ] [ r − 1 ] + 2 k dp[l+1][r-1]+2^k dp[l+1][r1]+2k。因此有: d p [ l ] [ r ] = d p [ l + 1 ] [ r ] + d p [ l + 1 ] [ r − 1 ] + 2 k dp[l][r]=dp[l+1][r]+dp[l+1][r-1]+2^k dp[l][r]=dp[l+1][r]+dp[l+1][r1]+2k
  5. S l = = ′ ( ′ S_l=='(' Sl==( S r = = ′ ? ′ S_r=='?' Sr==?,分析同上有: d p [ l ] [ r ] = d p [ l ] [ r − 1 ] + d p [ l + 1 ] [ r − 1 ] + 2 k dp[l][r]=dp[l][r-1]+dp[l+1][r-1]+2^k dp[l][r]=dp[l][r1]+dp[l+1][r1]+2k
  6. S l = = ′ ? ′ S_l=='?' Sl==? S r = = ′ ? ′ S_r=='?' Sr==?,产生四种新串。当 S l = = ′ ) ′ S_l==')' Sl==)时, S r = = ′ ( ′ S_r=='(' Sr==( S r = = ′ ) ′ S_r==')' Sr==)两种串产生的贡献之和为 d p [ l ] [ r − 1 ] dp[l][r-1] dp[l][r1];同理,当 S r = = ′ ( ′ S_r=='(' Sr==(时, S l = = ′ ( ′ S_l=='(' Sl==( S l = = ′ ) ′ S_l==')' Sl==)两种串产生的贡献之和为 d p [ l + 1 ] [ r ] dp[l+1][r] dp[l+1][r]。根据上述讨论我们将 S l = = ′ ) ′ S_l==')' Sl==) S r = = ′ ( ′ S_r=='(' Sr==(的情况计算了两次,但没计算 S l = = ′ ( ′ S_l=='(' Sl==( S r = = ′ ) ′ S_r==')' Sr==)的情况。再由3. 的分析,我们得到当 S l = = ′ ( ′ S_l=='(' Sl==( S r = = ′ ) ′ S_r==')' Sr==)时的贡献为 d p [ l + 1 ] [ r − 1 ] + 2 k dp[l+1][r-1]+2^k dp[l+1][r1]+2k,而 d p [ l + 1 ] [ r − 1 ] dp[l+1][r-1] dp[l+1][r1]其实就是当 S l = = ′ ) ′ S_l==')' Sl==) S r = = ′ ( ′ S_r=='(' Sr==(时的贡献。综上有: d p [ l ] [ r ] = d p [ l ] [ r − 1 ] + d p [ 1 + 1 ] [ r ] + 2 k dp[l][r]=dp[l][r-1]+dp[1+1][r]+2^k dp[l][r]=dp[l][r1]+dp[1+1][r]+2k

​ 复杂度: O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e3+5;
const ll mod=998244353;
ll dp[maxn][maxn],cnt[maxn],pow2[maxn]={1};
char s[maxn];
int main()
{
	cin>>(s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++)
		cnt[i]=cnt[i-1]+(s[i]=='?'),pow2[i]=(pow2[i-1]<<1)%mod;
	for(int i=2;i<=n;i++)
		for(int l=1,r=l+i-1;r<=n;l++,r++)
		{
			ll &x=dp[l][r],p=pow2[cnt[r-1]-cnt[l]];
			x=dp[l+1][r-1];
			if(s[l]==')') x=dp[l+1][r];
			if(s[r]=='(') x=dp[l][r-1];
			if(s[l]=='('&&s[r]==')') x=dp[l+1][r-1]+p;
			if(s[l]=='?'&&s[r]==')') x=dp[l+1][r]+dp[l+1][r-1]+p;
			if(s[l]=='('&&s[r]=='?') x=dp[l][r-1]+dp[l+1][r-1]+p;
			if(s[l]=='?'&&s[r]=='?') x=dp[l][r-1]+dp[l+1][r]+p;
			x%=mod;
		}
	cout<<dp[1][n]<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值