【XSY2564】sequence(字符串+DP)
【题目描述】
给定一个长度为的由组成的字符串,表示由字符串第到第位组成的十进制数字。
将它的某一个上升序列定义为:将这个字符串切割成段不含前导的串,切点分别为,使得。
请你求出该字符串的上升序列个数,答案对取模。
第一行一个整数,表示字符串长度;
第二行个内的字符,表示给出的字符串。
仅一行表示给出字符串的上升序列个数对取模的值。
6
123434
8
8
20152016
4
对于的数据满足:;
对于的数据满足:。
思路
看到这道题,特征十分明显:求方案数,数值较大(要mod),所以我们果断选择
我们设数组表示第一段以开头,长度为的方案数的和
于是,我们最后的答案为,表示第一段以开头,长度为的方案数的和
接着,我们设表示(以下就表示字符串)与的最长公共前缀
显而易见,我们得到
则我们在推状转方程时会有三种情况
,显而易见,这种情况下这一段直接到,所以值为
我们来比较一下两个相邻且长度相等为的字符串所组成的十进制数与的大小
若,那么满足要求,则有
dp[i][j]=dp[i+j][j]
若,因为两个字符串长度相等,若后者再往后多一位,还是比前者大,于是有
dp[i][j]=dp[i+j][j+1]
最后,因为要满足的定义,我们还要将加上,至于为什么,自行理解
现在,推完了状转方程,我们回过头来考虑怎么比较两个数的大小
我们可以比较与的大小,既可以比较两个数大小
但是我们考虑一种情况,若,那么事情就一发不可收拾了,于是我们要取。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n;
char s[5010];
int a[5010][5010];
int dp[5010][5010];
bool check(int i,int j)
{
int len=min(j-1,a[i][i+j]);
return s[i+len]<s[i+j+len];
}
int main()
{
scanf("%d %s",&n,s+1);
for(int i=n;i>0;i--)
{
for(int j=i+1;j<=n;j++)
{
if(s[i]==s[j])a[i][j]=a[i+1][j+1]+1;
}
}
for(int i=n;i>0;i--)
{
if(s[i]!='0')
{
dp[i][n-i+1]=1;
for(int j=1;j<=n-i;j++)
{
if(check(i,j))dp[i][j]=dp[i+j][j];
else dp[i][j]=dp[i+j][j+1];
}
for(int j=n-i;j>0;j--)dp[i][j]=(dp[i][j]+dp[i][j+1])%mod;
}
}
printf("%d\n",dp[1][1]);
}
梅子满树,清酒伊人
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律