CF909C python Indentation

博客围绕模拟赛中的一道Dp题展开。分析指出搜索时间会超时,应采用动态规划。设dp[i][j]为以i结尾、前面有j个空格的总方案数,分s[i - 1]为‘f’和‘s’两种情况推导转移方程,还考虑后缀和优化时间复杂度至O(n²),最后给出代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

这次模拟赛出的好bt,这道题被出成T1,只有一个人A了,而我却被卡到了80pts80pts80pts

分析

看一眼题目与数据范围,搜索时间一定炸,显然是一道DpDpDp

dp[i][j]dp[i][j]dp[i][j]为以iii结尾,前面有jjj个空格的总方案数。

我们可以分为两种情况:

1.s[i-1]=‘f’

这种情况比较简单,因为有一个限制是每一个fff下面必须不为空,所以说当前这个的位置必须是在上一个字符的下一层,也就是下一个包含在上一个中,

for example:


f
 x
 
x表示'f'或's'

于是我们就可以推出来这样一个转移方程:
dp[i][j]=dp[i−1][j−1](s[i−1]==′f′)dp[i][j] = dp[i - 1][j - 1](s[i-1]=='f')dp[i][j]=dp[i1][j1](s[i1]==f)

2.s[i-1]=‘s’

这种情况稍显复杂,因为如果上一个字符为sss的话,那么下面一个字符就可以在不超过上一个的层数的任何位置,设上一个在第x层,那么这一个位置就可以在x-1,x-2,x-3…2,1这一些层数在0~x-1的位置,故上一个dp[i−1][j]dp[i-1][j]dp[i1][j]的方案数可以加到dp[i][k](0<=k<=j)dp[i][k](0<=k<=j)dp[i][k](0<=k<=j)这里面。

for example:


  s
x

  s
 x
 
  s
  x
  
x表示'f'或's'

于是我们就可以推出来这样一个转移方程:
dp[i][j]=∑(dp[i−1][k])dp[i][j] = \sum(dp[i - 1][k])dp[i][j]=(dp[i1][k])

其中k>=j。

时间复杂度问题

如果第二种世界暴力写的话,可以发现最坏时间复杂度为O(n3)O(n^3)O(n3),绝对会T。于是考虑后缀和,优化一下时间复杂度,在第二种情况就可以O(n)O(n)O(n)更新,于是总的时间复杂度为O(n2)O(n^2)O(n2)

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define MOD 1000000007
const int MAXN = 5e3 + 5;
int n,sum[MAXN],dp[MAXN][MAXN],ans,Sum[2][MAXN];
char s[MAXN];
int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) {
		scanf("\n%c",&s[i]);
		if(s[i] == 'f') sum[i + 1] = sum[i] + 1;
		else sum[i + 1] = sum[i];
	}
	if(s[n] == 'f') return printf("0"),0;
	dp[1][0] = 1,Sum[0][0] = 1;
	for(int i = 2;i <= n;i ++) {
		if(s[i - 1] == 's')
		for(int j = sum[i];j >= 0;j --) {
			dp[i][j] += Sum[0][j],dp[i][j] %= MOD;
			Sum[1][j] = Sum[1][j + 1] + dp[i][j],Sum[1][j] %= MOD;
		}	
		else for(int j = sum[i];j >= 0;j --)
		dp[i][j] = dp[i - 1][j - 1],dp[i][j] %= MOD,Sum[1][j] = Sum[1][j + 1] + dp[i][j],Sum[1][j] %= MOD;
		memcpy(Sum[0],Sum[1],sizeof(Sum[1]));
	}
	for(int i = 0;i <= sum[n];i ++)
	ans += dp[n][i],ans %= MOD;
	printf("%d",ans);
	return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值