题意:
给一个字符串和一个单词,问单词在串中的组合数。
思路:
看到题想到了dp+kmp,推了一个别扭的转移方程,结果因为脑抽没过。。。
回头看了题解,比自己推得简单好多,而且发现不用kmp优化也不会超时。
dp[i] 表示0-i串的组合数,
dp[0] = 1, dp[i] = dp[i-1], (i-len+1, i)串匹配时 dp[i] += dp[i-len];
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MOD = 1e9+7;
const int MAXN = 1e5+10;
int dp[MAXN];
int main(int argc, char const *argv[])
{
int t;
cin >> t;
for(int k = 1; k <= t; k++)
{
string a, b;
cin >> a >> b;
dp[0] = 1;
for(int i = 1; i <= a.length(); i++)
{
dp[i] = dp[i-1];
if(i >= b.length() && a.substr(i-b.length(), b.length()) == b)
dp[i] += dp[i-b.length()];
dp[i] %= MOD;
}
cout << "Case #" << k << ": " << dp[a.length()] << endl;
}
return 0;
}
//复杂版。。。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const long long MOD = 1000000007;
int pLen, sLen;
int nxt[maxn], a[maxn];
long long dp[maxn];
char str[maxn], p[maxn];
void getNext(){
memset(a, 0, sizeof(a));
nxt[0] = -1, nxt[1] = 0;
for(int i = 2; i <= pLen; i++){
int k = i-1;
while(nxt[k] != -1 && p[i-1] != p[nxt[k]]){
k = nxt[k];
}
nxt[i] = nxt[k] + 1;
}
}
void KMP(){
int ans = 0, i = 0, j = 0;
while(1){
while(i < sLen && j < pLen){
while(i < sLen && j < pLen && str[i] == p[j]){
i++;
j++;
}
if(j < pLen){
j = nxt[j];
if(j == -1){
i++;
j = 0;
}
}
}
if(j != pLen || i == sLen){
if(j == pLen){
a[i-1] = 1;
}
break;
}else{
a[i-1] = 1;
j = nxt[j];
if(j == -1){
j = 0;
i++;
}
}
}
}
int main(){
int t, ans, res;
cin >> t;
for(int k = 1; k <= t; k++){
scanf("%s%s", str, p);
pLen = strlen(p);
sLen = strlen(str);
getNext();
KMP();
memset(dp, 0, sizeof(dp));
long long tmp = 0;
for(int i = pLen; i <= sLen; i++)
{
if(a[i-1])
{
dp[i] += 2 * dp[i-pLen] + 1 + tmp;
dp[i] %= MOD;
// printf("%d--\n", dp[i]);
tmp += dp[i-pLen] + 1;
tmp %= MOD;
}
else
dp[i] = dp[i-1];
if(a[i-pLen])
{
tmp += MOD - dp[i-2*pLen+1] - 1;
tmp %= MOD;
}
}
long long ans = dp[sLen] + 1;
ans %= MOD;
printf("Case #%d: %I64d\n", k, ans%MOD);
}
return 0;
}