【每日一题】「火」皇家烈焰
「火」皇家烈焰
https://ac.nowcoder.com/acm/problem/53683
题目描述
帕秋莉掌握了一种火属性魔法
由于钟爱扫雷游戏,帕秋莉把自己图书馆前的走廊看作一个一维的扫雷地图,她制造了很多烈焰,排在这条走廊内
现在帕秋莉告诉你一部分烈焰的分布情况,请你告诉她可能的情况有多少种
对于一个格子,里面会有以下几种字符:
0:这个格子没有烈焰,且其左右两个格子均没有烈焰
1:这个格子没有烈焰,且其左右两个格子中只有一个烈焰
2:这个格子没有烈焰,且其左右两个格子中均有烈焰
*:这个格子有烈焰
?:未告诉你本格情况
题解
很明显是一道dp的题目,我们考虑它的转移方程是怎么样的。由题目里的限制 可以得到,当前位置是否为烈焰与他前一位和后一位是否为烈焰都有关,并且当我们枚举到当前位置的时候前一位的前一位是没有用的,
所以我们设dp[i][j 0/1][k 0/1]表示当前在i为状态为j,i+1位的状态为k。所以dp[][][]转移方程就可以轻松的得到啦~
并且由于第0位,第n+1位都不可能为烈焰,所以我们在初始化和最后统计答案的时候要注意一下下
#pragma GCC optimize(2) #include<bits/stdc++.h> #define ls rt<<1 #define rs rt<<1|1 #define fi first #define se second #define pb push_back using namespace std; typedef long long ll; typedef vector<int> VI; typedef pair<int,int> pii; typedef pair<ll,ll> pll; const ll inf = 0x3f3f3f3f; const int mod = 1e9 + 7; const int maxn = 2e6 + 6; const int N = 1e3 + 4; const double eps = 1e-6; ll qpow(ll x,ll y){ll ans=1;x%=mod;while(y){ if(y&1) ans=ans*x%mod; x=x*x%mod; y>>=1;}return ans;} char s[maxn]; int n; ll ans,dp[maxn][2][2]; int main(){ scanf("%s",s+1); n=strlen(s+1); dp[0][0][0]=dp[0][0][1]=1; for(int i=1;i<=n;i++){ if(s[i]=='0'){ dp[i][0][0]=dp[i-1][0][0]; } if(s[i]=='1'){ dp[i][0][1]=dp[i-1][0][0]; dp[i][0][0]=dp[i-1][1][0]; } if(s[i]=='2'){ dp[i][0][1]=dp[i-1][1][0]; } if(s[i]=='*'){ dp[i][1][0]=(dp[i-1][0][1]+dp[i-1][1][1])%mod; dp[i][1][1]=(dp[i-1][0][1]+dp[i-1][1][1])%mod; } if(s[i]=='?'){ dp[i][0][0]=(dp[i-1][1][0]+dp[i-1][0][0])%mod; dp[i][0][1]=(dp[i-1][1][0]+dp[i-1][0][0])%mod; dp[i][1][0]=(dp[i-1][0][1]+dp[i-1][1][1])%mod; dp[i][1][1]=(dp[i-1][0][1]+dp[i-1][1][1])%mod; } } printf("%lld\n",dp[n][0][0]+dp[n][1][0]); }