P5270 無論怎樣神樹大人都會刪庫跑路
阿新 • • 發佈:2019-03-23
怎麽辦 end cout unsigned const fir .... 怎麽 ()
題目地址:P5270 無論怎樣神樹大人都會刪庫跑路
暴力模擬都會吧......
50分代碼:
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 6; int n, T, Q, m, c[N], r[N], mx, cnt, d[N], ans, s[N], now; vector<int> e[N]; queue<int> q; int main() { cin >> n >> T >> Q; for (int i = 1; i <= T; i++) { int x; scanf("%d", &x); mx = max(mx, x); ++c[x]; } for (int i = 1; i <= n; i++) { int len; scanf("%d", &len); while (len--) { int x; scanf("%d", &x); mx = max(mx, x); e[i].push_back(x); } } cin >> m; for (int i = 1; i <= m; i++) scanf("%d", &r[i]); for (int x = 0; x <= mx; x++) if (c[x] == d[x]) ++cnt; for (int i = 1; i <= m && i <= Q; i++) { for (unsigned int j = 0; j < e[r[i]].size(); j++) { int x = e[r[i]][j]; q.push(x); if (d[x] == c[x]) --cnt; ++d[x]; if (d[x] == c[x]) ++cnt; } while ((int)q.size() > T) { int x = q.front(); q.pop(); if (d[x] == c[x]) --cnt; --d[x]; if (d[x] == c[x]) ++cnt; } if (cnt == mx + 1) ++ans; } if (Q <= m) { cout << ans << endl; return 0; } Q -= m; for (int i = 1; i <= m; i++) { for (unsigned int j = 0; j < e[r[i]].size(); j++) { int x = e[r[i]][j]; q.push(x); if (d[x] == c[x]) --cnt; ++d[x]; if (d[x] == c[x]) ++cnt; } while ((int)q.size() > T) { int x = q.front(); q.pop(); if (d[x] == c[x]) --cnt; --d[x]; if (d[x] == c[x]) ++cnt; } if (cnt == mx + 1) ++now; s[i] = now; } cout << ans + now * (Q / m) + s[Q%m] << endl; return 0; }
模擬是 \(O(n)\) 的?
抱歉,假了
康康這組數據:
1 1e5 1e9
1 1 ... 1
1e5 1 1 ... 1
1e5
1 1 ... 1
你會發現
被卡成 \(O(n^2)\) 了!
怎麽辦?
罵出題人
我們發現瓶頸在這:
for (unsigned int j = 0; j < e[r[i]].size(); j++) { int x = e[r[i]][j]; q.push(x); if (d[x] == c[x]) --cnt; ++d[x]; if (d[x] == c[x]) ++cnt; } while ((int)q.size() > T) { int x = q.front(); q.pop(); if (d[x] == c[x]) --cnt; --d[x]; if (d[x] == c[x]) ++cnt; }
這個插入刪除是 \(O(n)\) 的
我們能不能把它搞成 \(O(1)\) 的?
答案是可以
考慮 Hash 思想
先看代碼:
#include <bits/stdc++.h> #define ull unsigned long long #define pii pair<int, int> using namespace std; const int N = 1e5 + 6; int n, T, Q, S[N], R[N], m, mx, len, ans, s[N], kkk; vector<int> e[N]; struct H { ull h[6]; H() { memset(h, 0, sizeof(h)); } } Hash[N], numS, now; vector<H> num[N]; deque<pii> q; inline ull RA() { return (ull)rand() * rand() * rand() * rand() * rand() * rand(); } inline void add(H &a, H &b) { for (int i = 0; i < 6; i++) a.h[i] += b.h[i]; } inline void del(H &a, H &b) { for (int i = 0; i < 6; i++) a.h[i] -= b.h[i]; } inline bool equ(H a, H b) { for (int i = 0; i < 6; i++) if (a.h[i] != b.h[i]) return 0; return 1; } int main() { srand((unsigned)time(0)); cin >> n >> T >> Q; for (int i = 1; i <= T; i++) { scanf("%d", &S[i]); mx = max(mx, S[i]); } for (int i = 1; i <= n; i++) { int len; scanf("%d", &len); while (len--) { int x; scanf("%d", &x); mx = max(mx, x); e[i].push_back(x); } } cin >> m; for (int i = 1; i <= m; i++) scanf("%d", &R[i]); for (int i = 0; i <= mx; i++) for (int j = 0; j < 6; j++) Hash[i].h[j] = RA(); for (int i = 1; i <= T; i++) add(numS, Hash[S[i]]); for (int i = 1; i <= n; i++) { int len = e[i].size(); num[i].resize(len); for (int j = len - 1; ~j; j--) add(num[i][j], Hash[e[i][j]]); for (int j = len - 2; ~j; j--) add(num[i][j], num[i][j+1]); } for (int i = 1; i <= m && i <= Q; i++) { add(now, num[R[i]][0]); len += e[R[i]].size(); q.push_back({R[i], 0}); while (len > T) { pii x = q.front(); q.pop_front(); del(now, num[x.first][x.second]); len -= e[x.first].size() - x.second; if (len < T) { int k = num[x.first].size() - (T - len); q.push_front({x.first, k}); add(now, num[x.first][k]); len = T; } } if (equ(now, numS)) ++ans; } if (Q <= m) { cout << ans << endl; return 0; } Q -= m; for (int i = 1; i <= m && i <= Q; i++) { add(now, num[R[i]][0]); len += e[R[i]].size(); q.push_back({R[i], 0}); while (len > T) { pii x = q.front(); q.pop_front(); del(now, num[x.first][x.second]); len -= e[x.first].size() - x.second; if (len < T) { int k = num[x.first].size() - (T - len); q.push_front({x.first, k}); add(now, num[x.first][k]); len = T; } } if (equ(now, numS)) ++kkk; s[i] = kkk; } cout << ans + kkk * (Q / m) + s[Q%m] << endl; return 0; }
我們給每個數若幹維隨機Hash值
for (int i = 0; i <= mx; i++)
for (int j = 0; j < 6; j++)
Hash[i].h[j] = RA();
一串數的Hash值定義為每個數的每一維Hash分別相加(unsigned long long自然溢出)
那麽如果兩個串任意排列後可以相同,這兩個串對應的每一維都應該相同
那麽插入和刪除就都可以做到 \(O(1)\) 了
P5270 無論怎樣神樹大人都會刪庫跑路