偏序 分塊+bitset
阿新 • • 發佈:2020-08-23
題目描述
給定一個有\(n\)個元素的序列,元素編號為\([1,n]\),每個元素有\(k\)個屬性\(p_1,p_2,p_3,...,p_k\) ,求序列中滿足 \(i<j\)且 \(1 \leq t \leq k\),\(p_{t,i}<p_{t,j}\) 的數對\((i,j)\)的個數。
輸入格式
第一行兩個整數 \(n\),\(k\),表示序列長度和屬性個數。
接下來\(k\) 行,每行 \(n\)個整數,第\(t\) 行第 \(i\)個數表示\(p_{t,i}\) 。
輸出格式
共1行,表示滿足要求的數對個數。
樣例
樣例輸入
5 4 1 4 5 2 3 3 5 2 1 4 2 3 4 1 5 2 3 1 5 4
樣例輸出
2
資料範圍與提示
對於\(30\%\)的資料\(n \leq 5000\),\(k \leq 6\)
對於\(100\%\)的資料\(1 \leq n \leq 40000\),\(k \leq 6\)。保證對於所有元素的\(p_t\)屬性組成一個\(1 - n\)的排列。
分析
這道題算上座標的話,維數達到了\(7\)維
如果用一些資料結構去維護的話,很可能會超時
其實我們用 \(bitset\) 就可以搞定這道題
對於每一維,我們用 \(bitset\) 去儲存小於\(i\)的數所在的位置
最後對於每一個位置\(i\),我們將這幾個維度作位與運算
最後統計下標小於\(i\)的位置中\(1\)的個數
這樣去處理時間複雜度為\(O(n \times k)\),空間複雜度為\(O(n^2 \times k)\)
而\(40000 \times 40000 \times 6\) 的\(bitset\)我們顯然是開不下的
因此我們考慮用時間換空間
我們可以用分塊的思想將時間複雜度和空間複雜度都均衡至\(O(nlogn\times k)\)
程式碼
#include <cstdio> #include <bitset> #include <cmath> #include <iostream> const int maxn = 4e4 + 5; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * f; } int n, m, a[8][maxn], rk[8][maxn], blo; std::bitset<maxn> b[8][305], now, js, ws; int main() { n = read(), m = read(); blo = sqrt(n); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { a[i][j] = read(); rk[i][a[i][j]] = j; } } for (int i = 1; i <= m; i++) { for (int j = 1; j * blo <= n; j++) { b[i][j] = b[i][j - 1]; for (int k = (j - 1) * blo + 1; k <= j * blo; k++) { b[i][j].set(rk[i][k]); } } } int ans = 0; ws.reset(); for (int i = 1; i <= n; i++) { now.set(); ws.set(i); now &= ws; for (int j = 1; j <= m; j++) { int shuyu = a[j][i] / blo; js.reset(); js |= b[j][shuyu]; for (int k = shuyu * blo + 1; k <= a[j][i]; k++) { js.set(rk[j][k]); } now &= js; } ans += now.count() - 1; } printf("%d\n", ans); return 0; }