思路
观察题目,我们可以发现当前这一层的位置选择只与上一层的位置和代码种类有关,那么我们可以设dp[i][j]表示第i层间隔为j个时的方案总数
同时用一个now来记录到第i层f的数量,表示最多能够间隔的距离(间隔从0开始)
那么最终答案就是
∑ i = 0 n o w \sum_{i=0}^{now} ∑i=0nowdp[n][i]
考虑两种状态
1.第i-1层为f
此时当前位置只能由dp[i-1][j-1]得来,则转移方程为
∑ j = 1 n o w \sum_{j=1}^{now} ∑j=1nowdp[i][j]=dp[i-1][j-1]
注意:now实际是当前最大间隔数+1
因为如果当前只有1个f,f只能在0,那么最远走到的间隔是1
以此类推
2.第i-1层为s
设x[i-1]表示第i-1层的s所在间隔
即当前层没有限制,最远能到的距离便是0~x[i-1]
如下图
我们可以发现当前位置方案即为上一层能让当前位置可取的位置的方案和
又因为所有间隔小于上层位置间隔的位置都可取,所以第j个位置的状态转移方程为:
∑ j = 0 x [ i − 1 ] d p [ i − 1 ] [ j ] \sum_{j=0}^{x[i-1]}{dp[i-1][j]} ∑j=0x[i−1]dp[i−1][j]
实际上就是一个后缀和
Q:为何不用乘法原理
A:因为每一个位置只能连1根线到当前位置,实际就是继承上一层的位置方案,求和即可
Code:
#include<cstdio>
#include<iostream>
using namespace std;
int n,a[5005],now;
long long dp[5005][5005],Ans;
char s[10];
bool p;
int main()
{
scanf("%d",&n);
gets(s);
for(int i=1;i<=n;i++)
{
gets(s);
a[i]=s[0]=='s'?1:2;
}
dp[1][0]=1;
for(int i=2;i<=n;i++)
{
if(a[i-1]==2){
for(int j=now+1;j>=1;j--)
{
dp[i][j]=dp[i-1][j-1];
}
now++;
}
else{
long long sum=0;
for(int j=now;j>=0;j--)
{
sum+=dp[i-1][j];
dp[i][j]+=sum;
dp[i][j]%=1000000007;
}
}
}
for(int i=0;i<=now;i++)
{
Ans=(Ans+dp[n][i])%1000000007;
}
printf("%lld",Ans);
}