首页 > 其他分享 >「SWTR-04」Lining up

「SWTR-04」Lining up

时间:2022-12-14 21:58:40浏览次数:60  
标签:int Lining sum SWTR up long type dp mod

链接:https://www.luogu.com.cn/problem/P6212

题目描述:有一个串,每个字符为\(A,B,?\)中的一个。

\(?\)会是\(A,B\)中等概率随机的一个字符,若有一个点为\(A\),其后面的点为\(B\),满意度会加\(-b\),若有一个点为\(B\),其后面的点为\(A\),满意度会加\(a\)。

求满意度\(<=m\)的概率。

题解:可以发现,产生贡献当且仅当该位置在\(A\)连通块与\(B\)连通块之间,而\(A\)连通块个数与\(B\)连通块个数个数的差的绝对值小于等于\(1\),而且与第一个元素与最后一个元素的取值相关,所以我们可以\(dp\)\(A,B\)分界线数,然后推出
\(B,A\)分界线数。

令\(dp_{i,j,0/1,0/1}\)表示第\(i\)个点,有\(j\)个\(A,B\)分界线,开端点为\(A\)或\(B\),末尾点为\(A\)或\(B\)的方案数。

则枚举\(?\)填什么然后转移可算出方案数,除以总方案数可得到答案。

当然此题空间限制过小,需要滚动数组优化。

#include<iostream>
#define mod 1000000007
using namespace std;
long long n,m,a,b,t,sum,type,dp[2][2021][2][2];
char s[2021];
long long fast_pow(long long a,int b)
{
	if (b==0)
		return 1;
	if (b&1)
		return fast_pow(a*a%mod,b/2)*a%mod;
	else
		return fast_pow(a*a%mod,b/2);
}
int main()
{
	cin>>n>>m>>a>>b;
	for (int i=1;i<=n;++i)
	{
		cin>>s[i];
		if (s[i]=='?')
			t++;
	}
	if (s[1]!='B')
		dp[0][0][1][1]=1;
	if (s[1]!='G')
		dp[0][0][0][0]=1;
	for (int i=2;i<=n;++i)
	{
		type^=1;
		for (int j=0;j<=n;++j)
			dp[type][j][0][0]=dp[type][j][0][1]=dp[type][j][1][0]=dp[type][j][1][1]=0;
		for (int j=0;j<=n;++j)
			for (int k=0;k<=1;++k)
			{
				if (s[i]!='B')
				{
					if (j>=1)
						dp[type][j][1][k]=(dp[type][j][1][k]+dp[type^1][j-1][0][k])%mod;
					dp[type][j][1][k]=(dp[type][j][1][k]+dp[type^1][j][1][k])%mod;
				}
				if (s[i]!='G')
				{
					dp[type][j][0][k]=(dp[type][j][0][k]+dp[type^1][j][1][k])%mod;
					dp[type][j][0][k]=(dp[type][j][0][k]+dp[type^1][j][0][k])%mod;
				}
			}
	}
	for (int i=0;i<=n;++i)
	{
		if (i*a-i*b>=m)
			sum=(sum+dp[type][i][1][1]+dp[type][i][0][0])%mod;
		if (i>0&&(i-1)*a-i*b>=m)
			sum=(sum+dp[type][i][1][0])%mod;
		if ((i+1)*a-i*b>=m)
			sum=(sum+dp[type][i][0][1])%mod;
	}
	cout<<sum*fast_pow(fast_pow(2,t),mod-2)%mod<<endl;
	return 0; 
}

标签:int,Lining,sum,SWTR,up,long,type,dp,mod
From: https://www.cnblogs.com/zhouhuanyi/p/16983692.html

相关文章