题目描述
简要题意:现在有一块长为 $L$ 的巧克力,我们可以将其切成若干段,不妨假设切成了 $m$ 段,每段的长度为 $a_i$,那么这种切法的价值就是 $\sum_{i=1}^ma_i^2$,现在给定 $n$ 个位置,这些位置不能切,求所有切法的价值和,答案对 $1e9+7$ 取模
$L\le 10^9,n\le 10^5$
Solution
我们考虑 $dp$,令 $f_i$ 表示切的位置在 $i$ 的价值和,容易得到 $f_i=\sum_{j=0}^{i-1}f_j(i-j)^2$
这个东西咋一看没法优化,但其实这个东西可以写成矩阵的形式,我们考虑用矩阵维护 $\sum_{i=0}^nf_i,\sum_{i=0}^n(n+1-i)f_i,\sum_{i=0}^n{(n+1-i)^2f_i}$,然后发现三个东西可以转移的,转移矩阵为
注意这个转移矩阵是左乘的,然后没法切的转移就是将第三列都减掉一个 $1$,时间复杂度 $O(n\log n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <iostream> #define maxn 100010 #define ll long long using namespace std;
const int p = 1000000007; inline int add(int x, int y) { return (x += y) >= p ? x - p : x; }
struct Matrix { static const int n = 4; int a[n + 1][n + 1]; inline void clear() { fill(a[0], a[0] + (n + 1) * (n + 1), 0); } Matrix() { clear(); } inline void setone() { for (int i = 1; i <= n; ++i) a[i][i] = 1; }
friend Matrix operator * (const Matrix &u, const Matrix &v) { Matrix w; for (int k = 1; k <= n; ++k) for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) w.a[i][j] = add(w.a[i][j], 1ll * u.a[i][k] * v.a[k][j] % p); return w; } } s[maxn];
Matrix pow(Matrix x, int n) { Matrix s; s.setone(); for (; n; n >>= 1, x = x * x) if (n & 1) s = s * x; return s; }
int n, L, a[maxn];
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> L >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; Matrix s, x, y; s.a[1][1] = s.a[2][1] = s.a[3][1] = 1; x.a[1][1] = x.a[1][3] = x.a[2][1] = x.a[2][2] = x.a[2][3] = x.a[3][1] = 1; x.a[3][2] = x.a[3][3] = 2; y.a[1][1] = y.a[2][1] = y.a[2][2] = y.a[3][1] = y.a[3][3] = 1; y.a[3][2] = 2; for (int i = 1; i <= n; ++i) { s = pow(x, a[i] - a[i - 1] - 1) * s; if (i <= n) s = y * s; } cout << (pow(x, L - 1 - a[n]) * s).a[3][1] << "\n"; return 0; }
|