vector g(n + 1, vector<ll>(m + 1)); for (int a = 0; a < min(n, m); a++) { for (int b = 1; b + a < min(n, m); b++) { auto work = [&](int l, int u) { int r = m - a - b + l, d = n - b - a + u; g[u][l]++; g[u][r]--; g[d][l]--; g[d][r]++; }; work(0, a); work(b, 0); work(a, a + b); work(a + b, b); } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (i) g[i][j] += g[i - 1][j]; if (j) g[i][j] += g[i][j - 1]; if (i && j) g[i][j] -= g[i - 1][j - 1]; cout << g[i][j] << " "; } cout << endl; } return0; }
multiset<int> s; while (n--) { int x; cin >> x; x %= k; s.insert(x); }
auto get = [&](int x) { auto it = s.lower_bound(k - x); return *(it == s.end() ? s.begin() : it); }; priority_queue<array<int, 3>> pq;
auto x = *s.begin(); // 取一个起点 s.erase(s.begin());
auto y = get(x); // 取 x 的一个出边 pq.push({ -(x + y) % k, y, x });
ll res = 0; while (!pq.empty()) { auto [w, x, p] = pq.top(); // 取出 x,p 是前驱 pq.pop();
if (!s.contains(x)) { // 相当于模板里 if (used[x]) // 用掉了 (p, x) 再给 p 找一个出边,保证每个点都恰好有一条出边在 pq 里 auto y = get(p); pq.push({ -(p + y) % k, y, p }); continue; } s.extract(x); // 相当于模板里 used[x] = true; res += -w;
if (s.empty()) break;
// 用掉了 (p, x) 再给 p 找一个出边,保证每个点都恰好有一条出边在 pq 里 auto y = get(p); pq.push({ -(p + y) % k, y, p });
// 给新加入 MST 的 x 找一个出边 y = get(x); pq.push({ -(x + y) % k, y, x }); }
for (int i = 1; i <= 200; i++) { _sg[i] = -1; } _sg[0] = 0; _sg[1] = 0; _sg[2] = 1; _sg[3] = 1; for (int x = 2; x <= 200; x++) { set<int> st; for (int i = 0; i <= x - 2; i++) { int j = x - i - 2; st.insert(_sg[i] ^ _sg[j]); } int mex = 0; for (auto s : st) { if (s == mex) mex++; else { _sg[x] = mex; break; } } _sg[x] = mex; }
// for (int x = 0; x <= 200; x++) { // assert(_sg[x] == sg(x)); // }
// for (int i = 0; i <= 500; i++) { // // cout << "sg[" << i << "] == " << sg[i] << endl; // cout << sg(i) << " "; // if (i % 34 == 33) { // cout << "\n"; // } // } int t; cin >> t;
vector<int> a(n); map<int, vector<int>> mp; for (int i = 0; i < n; i++) { cin >> a[i]; mp[a[i]].push_back(i); }
constint B = 500; map<pair<int, int>, ll> ans;
while (q--) { int x, y; cin >> x >> y;
if (x == y) { ll m = mp[x].size(); cout << (m - 1) * m / 2 << endl; continue; }
auto& mpx = mp[x]; auto& mpy = mp[y]; if (mpx.size() < B) { // B log n ll res = 0; for (auto p : mpx) { res += mpy.end() - lower_bound(mpy.begin(), mpy.end(), p); } cout << res << endl; } elseif (mpy.size() < B) { // B log n ll res = 0; for (auto p : mpy) { res += lower_bound(mpx.begin(), mpx.end(), p) - mp[x].begin(); } cout << res << endl; } else { if (ans.count({ x, y })) { // log n cout << ans[{ x, y }] << endl; } else { if (mpx.size() < mpy.size()) { ll res = 0; for (auto p : mpx) { res += mpy.end() - lower_bound(mpy.begin(), mpy.end(), p); } cout << res << endl; ans[{ x, y }] = res; } else { ll res = 0; for (auto p : mpy) { res += lower_bound(mpx.begin(), mpx.end(), p) - mp[x].begin(); } cout << res << endl; ans[{ x, y }] = res; } } } } return0; }
方法二 暴力枚举
仔细看代码,代码与根号分治没啥关系,都是遍历那个出现次数少的然后加个记忆化。所以完全可以把根号那个 if 去掉。也就是暴力的复杂度就是根号的,没必要再手动分治了。