【集训队作业2018】围绕着我们的圆环
我貌似開始爆OJ了
主要是因為預處理的范圍寫小,以及第一次寫帶刪除線性基,然后就調了好久/cy
如果把 \(A\) 看做一堆列向量,然后對于 \(C\) 的一個列向量 \(V\) ,以及對應列的 \(B\) 的列向量 \(B'\),由矩陣分塊,可得以下式子:
\[ V = (A_1 A_2 \dots A_q) B' \]
即 \(V\) 是由 \(A\) 線性組合出的。并且 \(C\) 的每個列向量也在 \(A\) 構成的線性空間里。
固定 \(V\) 和 \(A\) ,可得 \(B\) 的數量有 \(2^{q - r}\),其中 \(r = rank(A)\)
易得,對于確定的 \(V\) 和 \(A\), \(B\) 的數量是 \(2^{s(q - r)}\)
現在需要求 \(A\) 的數量。
因為 \(A\) \(V\) 分別初等行變換 \(B\) 的解不變,所以對于秩相同的 \(V\) 都對應著相同的方案。
發現固定 \(V\) 求 \(r = r'\) 的 \(A\) 有多少比較麻煩。所以對每個固定的 \(A\) 求 \(V\) 的貢獻,然后再除掉 \(V\) 的個數。
記 \(f_{n,m,r}\) 為 \(rank(A_{n,m}) = r\) 的方案數,顯然對于一個固定的 \(n\),可以 \(O(n^2)\) DP 出來,轉移只要討論是已經被表示還是一個新的基。
枚舉 \(r\) 易得 \(A\) 有 \(f_{p,q,r}\) 個,對于 \(C\) 只有 \(A\) 的基線性組合有效,所以考慮變換一下基,變為 \(A\) 的 \(r\) 個基,此時 \(C\) 的方案數不變,為 \(f_{r,s,x}\),其中 \(x = rank(C)\) (換基底就是乘上一個可逆矩陣)
此時答案很好表示
\[\textrm{Ans} = \sum_{r = x} \frac{f_{p,q,r} \times f_{r,s,x} \times 2 ^ {s(q - r)}}{f_{p,s,x}}\]
此時只要支持動態刪除的線性基即可。
我們維護每個向量是被哪幾個基異或出的。
考慮刪除時要找個基來頂替,有兩種情形:
實現時考慮到刪除一個基的時候,那個基的位置會被異或上選擇的那個基(根據異或性質)。
并且為了去掉要刪除的基的貢獻,同時計算新的基的貢獻,發現那個要刪除的會被貢獻兩次,即:
只要在被這個即將刪除的基異或過的位置異或上我們用來頂替的那個基即可。
同時我在一開始寫的時候寫麻煩了,實際上不需要一個下標對應一個基,因為刪除只和被哪些異或出有關。所以具體看代碼。
#include <bits/stdc++.h>const int MAXN = 1010; const int mod = 1000000007; typedef long long LL; void reduce(int & x) { x += x >> 31 & mod; } int mul(int a, int b) { return (LL) a * b % mod; } int fastpow(int a, int b) {int res = 1;while (b) {if (b & 1) res = mul(res, a);a = mul(a, a);b >>= 1;}return res; } typedef std::bitset<MAXN> B; B A[MAXN], frm[MAXN]; int rnk, bse[MAXN], isb[MAXN]; int n, P, m, Q, typ; void insert(int at, B x, int src) {static B fx; fx.reset(); fx[src] = true;isb[at] = 0;for (int i = m; i; --i) if (x.test(i)) {if (bse[i]) {x ^= A[bse[i]];fx ^= frm[bse[i]];} else {bse[i] = at;isb[at] = i;++rnk;break;}}A[at] = x, frm[at] = fx; } int remove(int at) {int ax = 0; isb[0] = 1001;for (int i = 1; i <= n; ++i)if (frm[i].test(at))if (isb[i] < isb[ax]) ax = i;rnk -= (bool) isb[ax];for (int i = 1; i <= n; ++i)if (i != ax && frm[i].test(at))frm[i] ^= frm[ax], A[i] ^= A[ax];if (isb[ax]) bse[isb[ax]] = 0;return ax; }int f[MAXN][MAXN], g[MAXN][MAXN], ansl[MAXN], pow2[MAXN * MAXN]; void predo() {pow2[0] = f[0][0] = g[0][0] = 1;int ran = std::max(n, m * P);for (int i = 1; i <= ran; ++i)reduce(pow2[i] = pow2[i - 1] * 2 - mod);ran = std::max(std::max(n, m), P);for (int i = 0; i < ran; ++i)for (int j = 0; j <= i; ++j) {reduce(f[i + 1][j] += mul(f[i][j], pow2[j]) - mod);reduce(f[i + 1][j + 1] += mul(f[i][j], pow2[n] - pow2[j] + mod) - mod);reduce(g[i + 1][j] += mul(g[i][j], pow2[j]) - mod);reduce(g[i + 1][j + 1] += mul(g[i][j], pow2[m] - pow2[j] + mod) - mod);}ran = std::min(n, P);for (int i = std::min(n, m); ~i; --i) {int & ans = ansl[i] = 0;for (int x = i; x <= ran; ++x)reduce(ans += (LL) f[P][x] * g[x][i] % mod * pow2[m * (P - x)] % mod - mod);ans = mul(ans, fastpow(f[m][i], mod - 2));} } int main() {std::ios_base::sync_with_stdio(false), std::cin.tie(0);std::cin >> n >> P >> m >> Q >> typ;predo();B tx;for (int i = 1; i <= n; ++i) {tx.reset();for (int j = 1, t; j <= m; ++j)std::cin >> t, tx[j] = t;insert(i, tx, i);}std::cout << ansl[rnk] << '\n';while (Q --> 0) {int at, t;std::cin >> at; at ^= typ * ansl[rnk];tx.reset();for (int j = 1; j <= m; ++j)std::cin >> t, tx[j] = t;insert(remove(at), tx, at);std::cout << ansl[rnk] << '\n';}return 0; }轉載于:https://www.cnblogs.com/daklqw/p/11508682.html
總結
以上是生活随笔為你收集整理的【集训队作业2018】围绕着我们的圆环的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 过滤ip
- 下一篇: [国家集训队]墨墨的等式