1. 程式人生 > >Codeforces 946F Fibonacci String Subsequences - 動態規劃 - 矩陣 - kmp

Codeforces 946F Fibonacci String Subsequences - 動態規劃 - 矩陣 - kmp

題目傳送門

  傳送門I

  傳送門II

  傳送門III

題目大意

  定義 F[0] = "0", F[1] = "1" ,以及當$n >1$時有 F[n] = F[n - 1] + F[n - 2] ,其中加號表示字串連線。

  給定01串$s$,問$s$在$F[x]$中所有子序列中出現的次數的和。

  先考慮一下暴力如何dp。設$f_{i, j}$表示考慮到當前個串的第$i$位,匹配到$s$的第$j$位時的方案數,再加一行一列記錄答案。

  然後換成$f_{l, r, s0, s1}$表示在$l - 1$時的狀態為$s0$,到$r$的狀態為$s1$的方案數,再加一行一列記錄答案。

  預處理$F[0], F[1]$的矩陣,直接矩陣乘法。

  好像可以設成匹配了$s$的$[l, r]$的方案數,這樣可以減小一點常數。

  開始把加號左右看反了,調了半天。sad....

Code

  1 /**
  2  * Codeforces
  3  * Problem#946F
  4  * Accepted
  5  * Time: 608ms
  6  * Memory: 4500k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11
using namespace std; 12 typedef bool boolean; 13 14 const int N = 105, M = 1e9 + 7; 15 16 int add(int a, int b) { 17 return ((a += b) >= M) ? (a - M) : (a); 18 } 19 20 int mul(int a, int b) { 21 return (a * 1ll * b % M); 22 } 23 24 int n, m; 25 int f[N]; 26
char str[N]; 27 int F[N][N][N]; 28 29 inline void init() { 30 scanf("%d%d", &n, &m); 31 scanf("%s", str + 1); 32 } 33 34 void kmp() { 35 f[0] = f[1] = 0; 36 for (int i = 1, j; i < n; i++) { 37 j = f[i]; 38 while (j && str[i + 1] != str[j + 1]) 39 j = f[j]; 40 f[i + 1] = ((str[i + 1] == str[j + 1]) ? (j + 1) : (0)); 41 } 42 } 43 44 void debugOut(int (*f)[N]) { 45 cerr << "BEGIN" << '\n'; 46 for (int i = 0; i <= n + 1; i++, cerr << '\n') 47 for (int j = 0; j <= n + 1; j++) 48 cerr << f[i][j] << " "; 49 cerr << "END" << '\n'; 50 } 51 52 inline void solve() { 53 int (*f0)[N] = F[0], (*f1)[N] = F[1]; 54 f0[0][0] = 1, f1[0][0] = 1; 55 for (int i = 1, j; i <= n; f0[i][i]++, i++) { 56 for (j = i - 1; j && str[j + 1] != '0'; j = f[j]); 57 j += (str[j + 1] == '0'); 58 f0[i - 1][j]++; 59 if (j == n) 60 f0[i - 1][n + 1]++; 61 } 62 for (int i = 1, j; i <= n; f1[i][i]++, i++) { 63 for (j = i - 1; j && str[j + 1] != '1'; j = f[j]); 64 j += (str[j + 1] == '1'); 65 f1[i - 1][j]++; 66 if (j == n) 67 f1[i - 1][n + 1]++; 68 } 69 f0[n + 1][n + 1] = f1[n + 1][n + 1] = 2; 70 int p = f[n]; 71 while (p && str[p + 1] != '1') 72 p = f[p]; 73 if (str[p + 1] == '1') 74 f1[n][p + 1]++, f1[n][n + 1] += (p == n - 1); 75 else 76 f1[n][0]++; 77 p = f[n]; 78 while (p && str[p + 1] != '0') 79 p = f[p]; 80 if (str[p + 1] == '0') 81 f0[n][p + 1]++, f0[n][n + 1] += (p == n - 1); 82 else 83 f0[n][0]++; 84 85 // debugOut(f0); 86 // debugOut(f1); 87 88 int n1 = n + 1; 89 for (int s = 2; s <= m; s++)//debugOut(F[s]), s++) 90 for (int i = 0; i <= n1; i++) 91 for (int j = 0; j <= n1; j++) 92 if (F[s - 1][i][j]) 93 for (int k = 0; k <= n1; k++) 94 F[s][i][k] = add(F[s][i][k], mul(F[s - 1][i][j], F[s - 2][j][k])); 95 printf("%d\n", F[m][0][n1]); 96 } 97 98 int main() { 99 init(); 100 kmp(); 101 solve(); 102 return 0; 103 }