【XR-1】分块
题目link:https://www.luogu.com.cn/problem/P5343
Part1:
首先这道题能够想到一个比较显然的 $dp$ 。
设 $dp[i]$ 表示长度为 $i$ 的序列有几种分块方式。
那么容易的出转移方程: $dp[i]$ $=$ $∑$ $dp[i$ $-$ $p[j]]$ $(1$ $≤$ $j$ $≤$ $l)$ ,其中 $l$ 为相同长度的块数, $p[j]$ 表示第 $j$ 个相同长度的块。
这样便可以 $O(n)$ 求出答案,可以通过 $60$$\%$ 的数据,但是 $100$$\%$ 的数据中 $0$ $≤$ $n$ $≤$ $10^{18}$ 。
Part2:
考虑优化,显然这个递推式是一个常系数线性递推,而这个 $l$ 的大小最大为 $100$ ,因此可以用矩阵快速幂优化。
因此只需要预处理出前 $100$ 的 $dp$ 值,之后构造初始向量和转移矩阵就可以了。
时间复杂度 $O($$x^3$ $*$ $log$ $k)$。
Code:
1 #include <cstdio> 2 #include <algorithm> 3 4 typedef long long LL; 5 6 const int MAXN = 100; 7 const LL MOD = 1e9 + 7; 8 9 LL n, dp[MAXN + 5]; 10 int pr, nf, prPiece[MAXN + 5], nfPiece[MAXN + 5]; 11 int len, piece[MAXN + 5], x; 12 13 struct Mat { 14 15 int N, M; 16 LL arr[MAXN + 5][MAXN + 5]; 17 18 Mat() {} 19 Mat(int _N, int _M, LL val = 0ll) { 20 N = _N, M = _M; 21 for(int i = 1; i <= N; ++i) { 22 for(int j = 1; j <= M; ++j) { 23 arr[i][j] = (i == j) ? val : 0ll; 24 } 25 } 26 } 27 28 // void print() { 29 // for(int i = 1; i <= N; ++i) { 30 // for(int j = 1; j <= M; ++j) { 31 // printf("%lld%c", arr[i][j], j == M ? '\n' : ' '); 32 // } 33 // } 34 // puts(""); 35 // } 36 37 }; 38 39 Mat operator* (const Mat &A, const Mat &B) { 40 41 Mat res(A.N, B.M); 42 43 for(int i = 1; i <= res.N; ++i) { 44 for(int j = 1; j <= res.M; ++j) { 45 for(int k = 1; k <= A.M; ++k) { 46 res.arr[i][j] += (A.arr[i][k] * B.arr[k][j]) % MOD; 47 res.arr[i][j] %= MOD; 48 } 49 } 50 } 51 52 return res; 53 } 54 55 Mat qpow(Mat A, LL k) { 56 57 Mat res(A.N, A.M, 1); 58 59 for(; k; k >>= 1) { 60 if(k & 1) res = res * A; 61 A = A * A; 62 } 63 64 return res; 65 } 66 67 int max(int a, int b) { 68 return a > b ? a : b; 69 } 70 71 int main() { 72 73 scanf("%lld", &n); 74 75 scanf("%d", &pr); 76 for(int i = 1; i <= pr; ++i) { 77 scanf("%d", &prPiece[i]); 78 } 79 80 scanf("%d", &nf); 81 for(int i = 1; i <= nf; ++i) { 82 scanf("%d", &nfPiece[i]); 83 } 84 85 std::sort(prPiece + 1, prPiece + pr + 1); 86 std::sort(nfPiece + 1, nfPiece + nf + 1); 87 int ptPr = 1, ptNf = 1; 88 while(ptPr <= pr && ptNf <= nf) { 89 if(prPiece[ptPr] < nfPiece[ptNf]) { 90 ++ptPr; 91 } 92 else if(prPiece[ptPr] > nfPiece[ptNf]) { 93 ++ptNf; 94 } 95 else { 96 if(prPiece[ptPr] != prPiece[ptPr - 1] && nfPiece[ptNf] != nfPiece[ptNf - 1]) { 97 piece[++len] = prPiece[ptPr]; 98 } 99 ++ptPr, ++ptNf; 100 } 101 } 102 103 for(int i = 1; i <= len; ++i) { 104 x = max(x, piece[i]); 105 } 106 107 Mat fac(x, x), vec(1, x); 108 dp[0] = 1ll; 109 for(int i = 1; i <= x; ++i) { 110 for(int j = 1; j <= len; ++j) { 111 if(i - piece[j] < 0) break; 112 dp[i] += dp[i - piece[j]]; 113 dp[i] %= MOD; 114 } 115 } 116 117 for(int i = 1; i <= x; ++i) { 118 vec.arr[1][i] = dp[x - i + 1]; 119 } 120 121 for(int i = 1; i <= len; ++i) { 122 fac.arr[piece[i]][1] = 1ll; 123 } 124 125 for(int i = 1; i <= fac.N; ++i) { 126 for(int j = 2; j <= fac.M; ++j) { 127 fac.arr[i][j] = (i == j - 1) ? 1ll : 0ll; 128 } 129 } 130 131 if(n <= x) { 132 printf("%lld\n", dp[n]); 133 } 134 else { 135 printf("%lld\n", (vec * qpow(fac, n - x)).arr[1][1]); 136 } 137 138 return 0; 139 }