【补题】The 3rd Universal Cup. Stage 15: Chengdu B. Athlete Welcome Ceremony
题意:给定一个字符串,由a、b、c、?组成,?可以由自己填写a、b、c任意一个字符,接下来只要求字符串相邻字符之间不重复,然后给出q个询问,每个询问给出多余的a,b,c字符,问有多少种方式填写满足要求的字符串
思路:
首先,非常明显的纯血dp,dp就是了,问题是怎么dp,个人的dp写法感觉有点愚蠢。
如果你想自己尝试写的话,很明显:
1.这个dp是一个类似线性的,也就是询问填写的地方即可。
2.到那个位置的时候,以什么结尾影响很明显,因为题目也就这么一个限制条件。
3.填写的数量情况很重要,毕竟决定了答案,这道题三维dp是至少的。
到此,你就完成了一个dp,我们假设四维dp[a][b][c][p],也就是填写的a数量,b数量,c数量,以及结尾。
但是这个dp是回答a+b+c严格等于空位的答案,我们要的是大于等于的,因为给的a,b,c数量不是严格等于空位,用什么呢?
考虑前缀和,本题第二个难点,那么是三维前缀和。
为什么是前缀和?因为继续使用dp,很难避免重复的情况,而前缀和,其实就是把当前位置的信息传递给更高层,本身的性质是保证不会重的,如果思考不清楚可以从低维前缀和考虑。
那么本题完成,代码:
写的不太好,dp是[a][b][c][p],实际上c可以由a,b直接算,应该能改成滚动数组,少302个三维是不是。
dp递推的代码应该可以写的更优美,交给你们了,鄙人就是傻子版
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
const int N=1e6+5;
const int MOD=1e9+7;
const int INF=1e18;int dp[305][305][305][3];
int ans[305][305][305];void solve(){int n,m;cin >> n >> m;string s;cin >> s;s=" "+s;s=s+" ";if(s[1]=='?') dp[1][0][0][0]=dp[0][1][0][1]=dp[0][0][1][2]=1;else if(s[1]=='a') dp[1][0][0][0]=1;else if(s[1]=='b') dp[0][1][0][1]=1;else if(s[1]=='c') dp[0][0][1][2]=1;int A=0,B=0,C=0;for(int i=0;i<s.size();i++){if(s[i]=='a') A++;else if(s[i]=='b') B++;else if(s[i]=='c') C++;}for(int i=2;i<=n;i++){for(int j=0;j<=i;j++){for(int k=0;k<=i-j;k++){int a=j,b=k,c=i-j-k;if(s[i]!='?'){if(a!=0 && s[i]=='a' && s[i+1]!='a' && s[i-1]!='a'){dp[a][b][c][0]+=dp[a-1][b][c][1];dp[a][b][c][0]+=dp[a-1][b][c][2];dp[a][b][c][0]%=MOD;dp[a][b][c][1]=dp[a][b][c][2]=0;}else if(b!=0 && s[i]=='b' && s[i+1]!='b' && s[i-1]!='b'){dp[a][b][c][1]+=dp[a][b-1][c][0];dp[a][b][c][1]+=dp[a][b-1][c][2];dp[a][b][c][1]%=MOD;dp[a][b][c][0]=dp[a][b][c][2]=0;}else if(c!=0 && s[i]=='c' && s[i+1]!='c' && s[i-1]!='c'){dp[a][b][c][2]+=dp[a][b][c-1][1];dp[a][b][c][2]+=dp[a][b][c-1][0];dp[a][b][c][2]%=MOD;dp[a][b][c][0]=dp[a][b][c][1]=0;}else{dp[a][b][c][0]=dp[a][b][c][1]=dp[a][b][c][2]=0;}}else{for(int l=0;l<3;l++){if(a!=0 && l==0 && s[i+1]!='a' && s[i-1]!='a'){dp[a][b][c][l]+=dp[a-1][b][c][1];dp[a][b][c][l]+=dp[a-1][b][c][2];}else if(b!=0 && l==1 && s[i+1]!='b' && s[i-1]!='b'){dp[a][b][c][l]+=dp[a][b-1][c][0];dp[a][b][c][l]+=dp[a][b-1][c][2];}else if(c!=0 && l==2 && s[i+1]!='c' && s[i-1]!='c'){dp[a][b][c][l]+=dp[a][b][c-1][0];dp[a][b][c][l]+=dp[a][b][c-1][1];}else{dp[a][b][c][l]=0;}dp[a][b][c][l]%=MOD;}}}}}int p=n-A-B-C;for(int i=0;i<=p;i++){for(int j=0;j<=p-i;j++){for(int l=0;l<3;l++){ans[i][j][p-i-j]+=dp[i+A][j+B][p-i-j+C][l],ans[i][j][p-i-j]%=MOD;}}}for(int i=1;i<=300;i++){for(int j=0;j<=300;j++){for(int k=0;k<=300;k++){ans[i][j][k]+=ans[i-1][j][k],ans[i][j][k]%=MOD;}}}for(int i=0;i<=300;i++){for(int j=1;j<=300;j++){for(int k=0;k<=300;k++){ans[i][j][k]+=ans[i][j-1][k],ans[i][j][k]%=MOD;}}}for(int i=0;i<=300;i++){for(int j=0;j<=300;j++){for(int k=1;k<=300;k++){ans[i][j][k]+=ans[i][j][k-1],ans[i][j][k]%=MOD;}}}for(int i=0;i<m;i++){int xa,xb,xc;cin >> xa >> xb >> xc;cout << ans[xa][xb][xc]%MOD << '\n';}}signed main(){IOS;int t=1;// cin >> t;while(t--){solve();}
}