分析
考虑相邻两个字符带来的约束。
- 若为 "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;
}
标签:PS,le,return,int,CodeForces,tot,1984F
From: https://www.cnblogs.com/smilemask/p/18297982