話說這題比賽時候過的好少,連題都沒讀TOT
先考慮dp求01串的不同子序列的個數。
dp[i][j]表示用前i個字符組成的以j為結尾的01串個數。
如果第i個字符為0,則dp[i][0] = dp[i-1][1] + dp[i-1][0] + 1,dp[i][1] = dp[i-1][1]
如果第i個字符為1,則dp[i][1] = dp[i-1][1] + dp[i-1][0] + 1,dp[i][0] = dp[i-1][0]
顯然這是線性遞推,我們考慮如何用矩陣表示這種遞推關系。
下面分別對應加入一個字符0或1時表示遞推關系的矩陣。
然后用線段樹維護每個區間的矩陣乘積就可以解決查詢操作了。
對於修改操作,我們給區間維護一個flip標記,表示該區間是否要翻轉,用線段樹區間更新的方法去更新flip標記就好了。
將一個區間翻轉后,它對應矩陣也要發生改變,這里我們只要將矩陣的第一列與第二列交換后再將第一行與第二行交換就好了。
#include <bits/stdc++.h> using namespace std; const long long mod = 1e9 + 7; const int mSize = 3; struct Matrix { long long v[mSize][mSize]; friend Matrix operator* (const Matrix& a, const Matrix& b) { Matrix c; for (int i = 0; i < mSize; i++) for (int j = 0; j < mSize; j++) { c.v[i][j] = 0; for (int k = 0; k < mSize; k++) c.v[i][j] += a.v[i][k] * b.v[k][j] % mod; c.v[i][j] %= mod; } return c; } }; const Matrix m[2] = {{1, 0, 0, 1, 1, 0, 1, 0, 1}, {1, 1, 0, 0, 1, 0, 0, 1, 1}}; Matrix data[100005 << 2]; bool flip[100005 << 2]; char s[100005]; void seq_build(int o, int l, int r) { if (l == r) data[o] = m[s[l] - '0']; else { int mid = (l + r) >> 1; seq_build(o << 1, l, mid); seq_build(o << 1 | 1, mid + 1, r); data[o] = data[o << 1] * data[o << 1 | 1]; } flip[o] = false; } void doFlip(Matrix& mat) { swap(mat.v[0][0], mat.v[0][1]); swap(mat.v[1][0], mat.v[1][1]); swap(mat.v[2][0], mat.v[2][1]); swap(mat.v[0][0], mat.v[1][0]); swap(mat.v[0][1], mat.v[1][1]); } void pushdown(int o) { if (flip[o]) { flip[o << 1] ^= flip[o]; flip[o << 1 | 1] ^= flip[o]; doFlip(data[o << 1]); doFlip(data[o << 1 | 1]); flip[o] = false; } } Matrix seq_query(int o, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) return data[o]; if (r < ql || qr < l) return {1, 0, 0, 0, 1, 0, 0, 0, 1}; int mid = (l + r) >> 1; pushdown(o); return seq_query(o << 1, l, mid, ql, qr) * seq_query(o << 1 | 1, mid + 1, r, ql, qr); } void seq_flip(int o, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) { flip[o] ^= 1; doFlip(data[o]); return; } if (r < ql || qr < l) return; int mid = (l + r) >> 1; pushdown(o); seq_flip(o << 1, l, mid, ql, qr); seq_flip(o << 1 | 1, mid + 1, r, ql, qr); data[o] = data[o << 1] * data[o << 1 | 1]; } int main() { int t; scanf("%d", &t); while (t--) { int n, q; scanf("%d%d", &n, &q); scanf("%s", s + 1); seq_build(1, 1, n); while (q--) { int op, l, r; scanf("%d%d%d", &op, &l, &r); if (op == 1) seq_flip(1, 1, n, l, r); else { Matrix mat = seq_query(1, 1, n, l, r); printf("%I64d\n", (mat.v[2][0] + mat.v[2][1]) % mod); } } } return 0; }
----------Update----------
抱歉很久沒有看cnblogs了,這里給出一個不太嚴謹的關於flip部分的證明