CodeForces - 1984F

分析

考虑相邻两个字符带来的约束。

  • 若为 "SS",则满足 $|b_i-b_{i+1}| \le m $
  • 若为 "PP",则满足 \(|b_{i+1}-b_i| \le m\)
  • 若为 "PS",则满足 \(tot_a=b_i+b_{i+1}\)
  • 若为 "SP",则满足 \(tot_a+a_{i}+a_{i+1}=b_i+b_{i+1}\)

发现可以枚举 "PS" 的位置来确定 \(tot_a\),为了防止全是 "S" 或 "P" 的情况,钦定 \(s_0=P,s_{n+1}=S\)
考虑确定了 \(tot_a\) 的情况下求出总方案数,可以设状态 \(dp_{i,0/1}\) 表示第 \(i\) 个选择了 S/P 的方案,转移比较显然,具体见代码。

代码

bool checkP(int i){
	return (s[i]=='P'||s[i]=='?');
}
		
bool checkS(int i){
	return (s[i]=='S'||s[i]=='?');
}
		
void Main(){
	mp.clear();
	int n=rd,m=rd,ans=0;
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
		b[i]=rd;
	b[0]=b[n+1]=0;
	s[0]='P',s[n+1]='S';
	for(int p=0;p<=n;p++){
		if(!checkP(p)||!checkS(p+1))
			continue;
		for(int i=0;i<=n+1;i++)
			dp[i][0]=dp[i][1]=0;
		dp[0][1]=1;
		int tot=b[p]+b[p+1];
		if(mp.count(tot)) 
			continue;
		mp[tot]=1;
		for(int i=1;i<=n+1;i++){
			if(checkS(i)){
				if(abs(b[i-1]-b[i])<=m)
					dp[i][0]=(dp[i][0]+dp[i-1][0])%mod;
				if(b[i]+b[i-1]==tot)
						dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;
			}
			if(checkP(i)){
				int mx=b[i]+b[i-1]-tot;
				mx=mx/2+mx%2;
				if(abs(mx)<=m) dp[i][1]=(dp[i][1]+dp[i-1][0])%mod;
				if(abs(b[i]-b[i-1])<=m)
					dp[i][1]=(dp[i][1]+dp[i-1][1])%mod;
			}
			if(s[i]=='S') dp[i][1]=0;
			if(s[i]=='P') dp[i][0]=0;
		}
		ans=(ans+dp[n+1][0])%mod;
	}
	cout<<ans<<endl;
}
posted @ 2024-07-12 14:50  SmileMask  阅读(6)  评论(0编辑  收藏  举报