hdu 4468 spy 构造kmp

题意:

  一个串s,经过多次被覆盖,求最小的原串s.

思路:

  将题目转换下,就是 一个串s的前缀能覆盖串r,且s本身是r的一个后缀.

  做法是首先考虑s的前缀能够覆盖r, 则我们从串r开始, 依次比较,并且记录上一次完全匹配(长度与s相同)的位置idx.

当出现ri != sj时,令 j = nxt[j], (这样做,而不是直接令J=0,是为了保证模式串最短),因为可能是从头开始的. 继续比较,

直到 j = 0, 意味着无法匹配.则将上一次的完全匹配位置 idx+1到 i,添加到模式串s中, 然后更新模式串的next函数,因为我们已经知道了. s( 1, length ),

这个时候模式串变成 s(1,length+(i-idx)),则只需要更新 s(length+1,length+(i-idx))的next函数值即可.

  当匹配完后, 这个时候的模式串s,并非一定会是 主串r的后缀. 例如 (aabbaa), 模式串s最终会得到abb, 但是其不是r的后缀.

我们可以知道最后一次完全匹配是在 4的位置,  则我们应该再将 (5,6)添加到模式串s中,然后就得到了 abbaa, 即为最终答案.

View Code
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 100;

LL dp[10][N][N];
int Mod;
int a[N], b[N], A[10];
LL res[N];

LL dfs( bool less, int length, int sum, int mod ){
    if( length == 0 )
        return less && (sum==Mod) && (mod==0);
    if( less && (dp[length][sum][mod]!=-1) ) return dp[length][sum][mod];
    LL tmp = 0;    
    for(int x = 0; x < 10; x++){
        if( !less && (x>A[length-1]) ) break;    
        tmp += dfs( less || (x<A[length-1]), length-1, sum+x, (mod*10+x)%Mod );    
    }
    if( less ) dp[length][sum][mod] = tmp;
    return tmp;
}
LL solve( int x ){//x本身不被计算
    int tmp = x, L = 0;
    while( tmp ) A[L++] = tmp%10, tmp /= 10;
    //reverse( A, A+L );
    LL tot = 0;
    return dfs( false, L, 0, 0 );
}
int main(){
    int t;
    scanf("%d", &t);
    for(int i = 0; i < t; i++)
        scanf("%d%d", &a[i], &b[i] );
    memset( res, 0, sizeof(res));
    for(Mod = 1; Mod < N; Mod++){
        memset( dp, -1, sizeof(dp));
        for(int i = 0; i < t; i++ )
            res[i] += solve( b[i]+1 ) - solve( a[i] );
    }
    for(int i = 0; i < t; i++)
        printf("Case %d: %lld\n", i+1, res[i] );
    return 0;
}
原文地址:https://www.cnblogs.com/yefeng1627/p/3051694.html