hihocoder#1807 : 好的数字串(DP+KMP)

版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/82112834

时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个数字字符串S,如果一个数字字符串(只包含0-9,可以有前导0)中出现且只出现1次S,我们就称这个字符串是好的。

例如假设S=666,则1666、03660666是好的,6666、66、123不是好的;假设S=1212,则01212、12123是好的,121212、121是不好的。

请你计算长度为N的数字字符串中,有多少个是好的。由于总数可能很大,你只需要输出总数模1000000007的余数。

输入
一个整数N和一个数字串S。

对于30%的数据,1 ≤ N ≤ 8

对于100%的数据,1 ≤ N ≤ 1000,1 ≤ |S| ≤ N。

输出
一个整数代表答案。

样例输入
6 1212
样例输出
298

思路:CF-1015F的基础上做了些改变。

但思路不变,还是DP+KMP。

d [ i ] [ j ] [ 0 / 1 ] 表示构造了长度为 i 的数字串,其中以 i 为结尾匹配的长度是 j 0 / 1 表示该串已经(还未)出现过匹配的方案数。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
char s[MAX];
int f[MAX];
int d[MAX][MAX][2];
void getfail()
{
    int n=strlen(s);
    f[0]=f[1]=0;
    for(int i=1;i<n;i++)
    {
        int j=f[i];
        while(j&&s[i]!=s[j])j=f[j];
        f[i+1]=(s[i]==s[j]?j+1:0);
    }
}
int main()
{
    int n;
    scanf("%d%s",&n,s);
    getfail();
    int m=strlen(s);
    d[0][0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            if(j<m)
            {
                for(int k=0;k<=9;k++)
                {
                    if(k==s[j]-'0')//当前字符匹配
                    {
                        (d[i][j+1][0]+=d[i-1][j][0])%=MOD;         //一次都未匹配的串
                        if(j+1<m)(d[i][j+1][1]+=d[i-1][j][1])%=MOD;//已经匹配过的串
                    }
                    else//当前字符不匹配,利用nex数组转移
                    {
                        int nex=j;
                        while(nex&&s[nex]!=k+'0')nex=f[nex];
                        if(s[nex]==k+'0')nex++;
                        (d[i][nex][0]+=d[i-1][j][0])%=MOD;
                        (d[i][nex][1]+=d[i-1][j][1])%=MOD;
                    }
                }
            }
            if(j==m)
            {
                for(int k=0;k<=9;k++)//对d[i-1][m][0]做转移,即对刚匹配完的串做转移
                {
                    int nex=m;
                    while(nex&&s[nex]!=k+'0')nex=f[nex];
                    if(s[nex]==k+'0')nex++;
                    if(nex==m)continue;
                    (d[i][nex][1]+=d[i-1][m][0])%=MOD;
                }
            }
        }
    }
    int ans=d[n][m][0];
    for(int i=0;i<m;i++)(ans+=d[n][i][1])%=MOD;
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/82112834