【XSY2564】sequence(字符串+DP)

(Description)

【题目描述】

给定一个长度为(n)的由(['0'..'9'])组成的字符串(s)(v[i,j])表示由字符串(s)(i)到第(j)位组成的十进制数字。

将它的某一个上升序列定义为:将这个字符串切割成(m)段不含前导('0')的串,切点分别为(k_{1},k_{2}...k_{m-1}),使得(v[1,k_{1}]<v[k_{1}+1,k_{2}]<...<v[k_{m-2}+1,k_{m-1}])

请你求出该字符串(s)的上升序列个数,答案对(10^9+7)取模。


(Input)

第一行一个整数(n),表示字符串长度;

第二行(n)(['0'..'9'])内的字符,表示给出的字符串(s)


(Output)

仅一行表示给出字符串(s)的上升序列个数对(10^9+7)取模的值。


(SampleInput1)

6

123434


(SampleOutput1)

8


(SampleInput2)

8

20152016


(SampleOutput2)

4


(Hint)

对于(30\%)的数据满足:(n<=10)

对于(100\%)的数据满足:(n<=5000)


思路

看到这道题,特征十分明显:求方案数,数值较大(要mod),所以我们果断选择(dp)

我们设数组(dp[i][j])表示第一段以(i)开头,长度为(jsim (n-i+1))的方案数的和

于是,我们最后的答案为(dp[1][1]),表示第一段以(1)开头,长度为(1sim n)的方案数的和

接着,我们设(a[i][j])表示(s[i][n])(以下(s)就表示字符串)与(s[j][n])的最长公共前缀

显而易见,我们得到(s[i][i+a[i][j]-1]=s[j][j+a[i][j]-1])

则我们在推状转方程时会有三种情况

(1.) (dp[i][n-i+1]=1),显而易见,这种情况下这一段直接到(n),所以值为(1)
(2.) 我们来比较一下两个相邻且长度相等(j)的字符串所组成的十进制数(s[i][i+j-1])(s[i+j][i+2 imes j-1])的大小

(2.1)(s[i][i+j-1]<s[i+j][i+2 imes j-1]),那么满足要求,则有

dp[i][j]=dp[i+j][j]

(2.2)(s[i][i+j-1]ge s[i+j][i+2 imes j-1]),因为两个字符串长度相等,若后者再往后多一位,还是比前者大,于是有

dp[i][j]=dp[i+j][j+1]

最后,因为要满足(dp[i][j])的定义,我们还要将(dp[i][j])加上(dp[i][j+1]),至于为什么,自行理解

现在,推完了状转方程,我们回过头来考虑怎么比较两个数的大小

我们可以比较(s[i][i+a[i][i+j]])(s[i+j][i+j+a[i][i+j]])的大小,既可以比较两个数大小

但是我们考虑一种情况,若(i+a[i][i+j]>i+j-1),那么事情就一发不可收拾了,于是我们要取(min(j-1,a[i][j]))


代码:

#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
",dp[1][1]);
}

原文地址:https://www.cnblogs.com/ShuraEye/p/11402808.html