之前沒做出這道題是因爲缺少自己的分析。
別人給你提供了一些思路,如果你照着做下去覺得可以比較順利,就繼續;如果總覺得想不通,就及時丟掉,自己想辦法做。
從這個圖中我們可以發現一些規律:原串不能產生原串(先不考慮原串中有重複的),能產生其他n-1個串。
第0步,原串是1,其他都是0,總和sum爲1;
第1步:原串產生其他串1,其他串產生原串0,原串爲0,其他串都爲1。即原串:sum – d[0], 其他i串:sum-d[i]。sum爲2
第2步:原串產生其他串0,其他串產生原串1,原串爲2,其他串都爲1。即原串:sum – d[0], 其他i串:sum-d[i]。sum爲4
第3步:原串產生其他串2,其他串產生原串1,原串爲2,其他串都爲3。即原串:sum – d[0], 其他i串:sum-d[i]。sum爲8
……
根據這些,我們設dp[i][j]表示第i步第j個串有多少種,
狀態轉移方程:dp[i][j]= sum[i- 1]-dp[i - 1][j];
最後我們只需枚舉要求的串在所給串中有多少個匹配位置,就把匹配位置的個數加起來即可。
優化:由於求第i步時我們只用到第i-1步,因此可用二層滾動數組;出了原串,其餘串的個數相同,我們可以只保存原串,和第一個串。因此dp[2][2]即可。複雜度爲O(k)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
const LL M = 1000000007;
LL dp[2][2], sum[2];
char b[1010], e[1010];
inline LL Mod(LL x)
{
return (x + M) % M;
}
int main()
{
//freopen("input.txt", "r", stdin);
int K, k, len;
scanf("%s %s %d", b, e, &K);
k = 0;
dp[k][0] = 1;
sum[k] = 1;
len = strlen(b);
for(int i = 1; i <= K; i++){
k ^= 1;
for(int j = 0; j < 2; j++)
dp[k][j] = Mod(sum[k ^ 1] - dp[k ^ 1][j]);
sum[k] = Mod(dp[k][0] + (len - 1) * dp[k][1]);
}
LL ans = 0;
for(int i = 0, j, l; i < len; i++){
for(j = 0, l = i; j < len; j++, l = (l + 1) % len){
if(b[l] != e[j]) break;
}
if(j >= len){
ans = i ? Mod(ans + dp[k][1]) : Mod(ans + dp[k][0]);
}
}
printf("%I64d\n", ans);
return 0;
}