题目描述
【题目背景】
Tom又一次地在追Jerry。Jerry跑进了一个神奇的跑道,Tom也跟了进去。Jerry想利用这个跑道让Tom摔倒,这样就不会被追上了。Jerry正在全力奔跑,所以就把这个计算任务交给你了。
【题目描述】
Jerry初始时在地面上的入口处。在跑道入口,以及在跑道中每跑过一秒就会遇到一个分岔口,一边是上坡跑道,一边是下坡跑道,跑道都是通向前方,是不会形成环的。Jerry也没有时间回头看Tom是否追上,所以他只会全力向前奔跑,而不会停下或者向回跑。每一秒在上坡跑道高度会上升1米,在下坡跑道高度会下降1m。Jerry通过告示牌知道这个跑道从入口到每个出口都恰好要跑T秒,也就是恰好在跑过T秒后就没有分岔口,出跑道了。Jerry也知道Tom会摔倒当且仅当它跑过了一段特定的上坡下坡的路段。Jerry要求在跑完后仍然在地面上(即出口的高度等于入口的高度)。不幸的是,前几天刚下过大雨,地面以下的跑道(即高度小于入口高度的跑道)都有积水,无法通行。Jerry想知道有多少种符合条件的选择跑道的方案(即有多少个出口对应的路径)能让Tom在这过程中摔倒,结果对1000000007取模。
输入
第一行一个正整数T,表示Jerry跑道上的时间。第二行一个仅有字母‘D’和‘U’构成的字符串S,表示Tom要摔倒的话要连续经过这样一段上下坡的路径,其中‘D’表示下坡,‘U’表示上坡。
输出
一行一个整数,表示符合条件且能让Tom摔倒的选择跑道的方案数对1000000007取模后的结果。
样例输入
【输入样例1】
2
UD
【输入样例2】
6
DDU
【输出样例1】
1
【输出样例2】
1
数据范围限制
对于50%的数据,1≤|S|≤T≤16。
对于另外10%的数据,T是奇数。
对于100%的数据,1≤|S|≤T≤200,S仅由‘U’和‘D’构成。
思路
一开始还想要暴搜,当我打完后,突然发现要去重。。。(机房惨案
设
g
[
i
,
j
]
g[i,j]
g[i,j]为第
i
i
i秒高度为
j
j
j的最优解,最后输出
g
[
n
,
0
]
g[n,0]
g[n,0]
为了判重,我们要设一个
f
[
i
,
j
]
f[i,j]
f[i,j]为第
i
i
i秒高度为
j
j
j的最优解 (吧)
但是因为有特定的一段高度,so,我们的
g
g
g要多加一些东西
举个栗子:
DDDUU
- down了三次,那必须在高度大于等于3的地方转移过来
- down的长度为3,那么时间就用了3
- 最后高度为-1,那么高度就要从 高度+(-1)转移过来
那么g的转移方程还有
for(int j=3;j<=i;j++)
g[i+3][j+(-1)]+=f[i][j]-g[i][j];//-g[i][j]是因为在之前"这一段特定高度"已经做过了,简称“判重”
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
const int mo=1000000007;//一定要记得%
long long f[1000][1000],g[1000][1000];
int n,m,d,m1;
string s;
int main(){
//freopen("track.in","r",stdin);
//freopen("track.out","w",stdout);
scanf("%d",&n);
cin>>s;
int d=0;
for(int i=0;i<s.size();i++){
if(s[i]=='D')d--;
else d++;
m1=max(m1,-d);
}
f[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++){
if(j>0)f[i][j]=f[i-1][j-1],g[i][j]=(g[i][j]+g[i-1][j-1])%mo;
if(i>0)f[i][j]=(f[i-1][j+1]+f[i][j])%mo,g[i][j]=(g[i-1][j+1]+g[i][j])%mo;
}
for(int j=m1;j<=i;j++)
g[i+s.size()][j+d]=(g[i+s.size()][j+d]+f[i][j]-g[i][j])%mo;
}
printf("%lld",g[n][0]);
}