【题目背景】
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
【输出样例 1】
1
【输入样例 2】
6
DDU
【输出样例 2】
1
【数据规模与约定】
对于 50%的数据,1≤|S|≤T≤16。
对于另外 10%的数据,T 是奇数。
对于 100%的数据,1≤|S|≤T≤200,S 仅由‘U’和‘D’构成。
题解:
是kmp字符串匹配
设dp[i][j][k]:第i秒时,高度为j,成功匹配第k个的方案数
状态转移方程式
for(int i=0;i<t;i++){
for(int j=0;j<=min(i,t-i);j++){
for(int k=0;k<tot;k++){
if(s[k]==‘U’){
dp[i+1][j+1][k+1]=(dp[i+1][j+1][k+1]+dp[i][j][k])%mod;
if(j)
dp[i+1][j-1][fail[k][0]]=(dp[i+1][j-1][fail[k][0]]+dp[i][j][k])%mod;
}
else{
dp[i+1][j+1][fail[k][1]]=(dp[i+1][j+1][fail[k][1]]+dp[i][j][k])%mod;
if(j)
dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k])%mod;
}
}
dp[i+1][j+1][tot]=(dp[i+1][j+1][tot]+dp[i][j][tot])%mod;
if(j)
dp[i+1][j-1][tot]=(dp[i+1][j-1][tot]+dp[i][j][tot])%mod;
}
}
其中fail[k][0]表示用D匹配失败时可以满足的前缀是多长
fail[k][1]表示用U匹配失败时可以满足的前缀是多少
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int t,tot=-1;
char s[205];
long long dp[205][205][205],fail[205][2],next[205];
int read(){
int num=0;
char ch=getchar();
while(ch>'9'||ch<'0'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<1)+(num<<3)+ch-'0';
ch=getchar();
}
return num;
}
void work(){
int k=0;
for(int i=1;i<tot;i++){
while(k&&s[k]!=s[i])
k=next[k];
if(s[k]==s[i])
k++;
next[i+1]=k;
}
fail[0][s[0]=='U']=1;
for(int i=1;i<=tot;i++){
k=i;
while(k&&s[k]!='U')
k=next[k];
fail[i][1]=k+1;
if(!k&&s[0]=='D')
fail[i][1]=0;
k=i;
while(k&&s[k]!='D')
k=next[k];
fail[i][0]=k+1;
if(!k&&s[0]=='U')
fail[i][0]=0;
}
}
int main(){
t=read();
char ch=getchar();
while(ch>10){
s[++tot]=ch;
ch=getchar();
}tot+=1;
work();
dp[0][0][0]=1;
for(int i=0;i<t;i++){
for(int j=0;j<=min(i,t-i);j++){
for(int k=0;k<tot;k++){
if(s[k]=='U'){
dp[i+1][j+1][k+1]=(dp[i+1][j+1][k+1]+dp[i][j][k])%mod;
if(j)
dp[i+1][j-1][fail[k][0]]=(dp[i+1][j-1][fail[k][0]]+dp[i][j][k])%mod;
}
else{
dp[i+1][j+1][fail[k][1]]=(dp[i+1][j+1][fail[k][1]]+dp[i][j][k])%mod;
if(j)
dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k])%mod;
}
}
dp[i+1][j+1][tot]=(dp[i+1][j+1][tot]+dp[i][j][tot])%mod;
if(j)
dp[i+1][j-1][tot]=(dp[i+1][j-1][tot]+dp[i][j][tot])%mod;
}
}
printf("%d",dp[t][0][tot]);
}