HDOJ 5763 Another Meaning

题意

给两个字符串a和b,b有两义性,求a一共有多少种可能的意思。

思路

首先KMP预处理出所有b是a子串的末尾位置,然后基础dp就可以了。
如果i位置是子串末尾则dp[i] = dp[i-1] + dp[i-lenb] + 1否则直接转移。

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define LL long long
#define Lowbit(x) ((x)&(-x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1|1
#define MP(a, b) make_pair(a, b)
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const int maxn = 1e5 + 7;
const double eps = 1e-8;
const double PI = acos(-1.0);
typedef pair<int, int> pii;

bool ok[maxn];
int dp[maxn];
char a[maxn], b[maxn];

void getnext(char *p, int n, int *next)
{
    int i = 0, j = -1;
    next[0] = j;
    while (i < n)
    {
        while (j != -1 && p[j] != p[i])
            j = next[j];
        i++, j++;
        if (j >= n)
            next[i] = next[j-1];
        else
            next[i] = j;
    }
}
void kmp(char *p, int n, char *s, int m)
{
    int next[10005];
    getnext(p, n, next);
    int i = 0, j = 0;
    while (i < m)
    {
        while (j != -1 && p[j] != s[i])
            j = next[j];
        i++, j++;
        if (j == n)
        {
            ok[i-1] = 1;
            j = next[j];
        }
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d", &T);
    for (int ncase = 1; ncase <= T; ncase++)
    {
        scanf("%s%s", a, b);
        memset(ok, 0, sizeof(ok));
        kmp(b, strlen(b), a, strlen(a));
        memset(dp, 0, sizeof(dp));
        dp[0] = ok[0];
        int len = strlen(a);
        int lenb = strlen(b);
        for (int i = 1; i < len; i++)
        {
            dp[i] = dp[i-1];
            if (ok[i]) dp[i] = (dp[i] + dp[i-lenb] + 1) % MOD;
        }
        printf("Case #%d: %d\n", ncase, dp[len-1] + 1);
    }
    return 0;
}

你可能感兴趣的:(dp,HDOJ,计数DP,KMP)