CF176B Word Cut(计数 dp)

Description

求经过 k k k 次将 S S S 划分成两部分并交换使 S S S 串变成 T T T 串的方案数并对 1 0 9 + 7 10^9 + 7 109+7 取模。

2 ≤ ∣ S ∣ ≤ 1000 , 0 ≤ k ≤ 1 0 5 2 \leq |S| \leq 1000, 0 \leq k \leq 10^5 2S1000,0k105

Solution

可以发现,只要能从一个串变成一个串,都可以通过仅一次变换得到,所以先预处理出一个 c n t cnt cnt 来表示原串通过一次变换有多少个其它串。暴力和 kmp 都可以,由于数据范围不大所以选择前者。

f i , 0 f_{i,0} fi,0 为经过 i i i 次变换所产生的原串个数, f i , 1 f_{i,1} fi,1 为产生其它串的个数。因为最后要得到 T T T,我们把 T T T 看作原串。那么转移要考虑原串变原串,原串变其它串,其它串变其它串,其它串变原串。

  • 得到原串的情况: f i − 1 , 1 f_{i-1,1} fi1,1 个其它串中,每个其它串可以通过一次变换得到 c n t cnt cnt 个原串。 f i − 1 , 0 f_{i-1,0} fi1,0 个原串中,每个原串通过一次变换得到除了自己以外 c n t − 1 cnt - 1 cnt1 个原串。如果算上自己的话,相当于没变换所以不合法。

  • 得到其它串的情况: f i − 1 , 0 f_{i-1,0} fi1,0 个原串中,每个原串可以通过一次变换得到 ∣ S ∣ − c n t |S| - cnt Scnt 个其他串。 f i − 1 , 1 f_{i-1,1} fi1,1 个其他串中,每个其他串可以通过一次变换得到除了自己以外的 ∣ S ∣ − c n t − 1 |S| - cnt - 1 Scnt1 个其他串。

综上所述,转移方程如下

f 0 , s ≠ t = 1 f_{0,s \not=t} = 1 f0,s=t=1

f i , 0 = c n t × f i − 1 , 1 + ( c n t − 1 ) × f i − 1 , 0 f_{i,0} = cnt \times f_{i-1,1} + (cnt - 1) \times f_{i-1,0} fi,0=cnt×fi1,1+(cnt1)×fi1,0

f i , 1 = ( ∣ S ∣ − c n t ) × f i − 1 , 0 + ( ∣ S ∣ − c n t − 1 ) × f i − 1 , 1 f_{i,1} = (|S| - cnt) \times f_{i-1,0} + (|S| - cnt - 1) \times f_{i-1,1} fi,1=(Scnt)×fi1,0+(Scnt1)×fi1,1

a n s = f k , 0 ans =f_{k,0} ans=fk,0

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, p = 1e9 + 7;
char s[N], t[N];
ll f[N][2];
int n, k, cnt;  
bool check(int l, int r) {
	int j = 0;
	for (int i = l; i <= r; i++) if (s[i] != t[++j]) return 0;
	return 1;
}
int main() {
	scanf("%s%s%d", s + 1, t + 1, &k); 
	n = strlen(s + 1); 
	for (int i = 1; i <= n; i++) s[i + n] = s[i];
	for (int i = 1; i <= n; i++) if (check(i, i + n - 1)) cnt++;
	f[0][!check(1, n)] = 1;
	for (int i = 1; i <= k; i++) {
		f[i][0] = (cnt * f[i - 1][1] % p + (cnt - 1) * f[i - 1][0] % p) % p;
		f[i][1] = ((n - cnt) * f[i - 1][0] % p + (n - cnt - 1) * f[i - 1][1] % p) % p;
	}
	printf("%lld\n", f[k][0]);
	return 0;
} 
posted @ 2020-02-20 10:57  ylxmf2005  阅读(55)  评论(0)    收藏  举报