【NOIP模拟赛】track

【题目背景】
在这里插入图片描述
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]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值