复杂度证明比题难:题解:P12522 [Aboi Round 1] 限りなく灰色へ
[Aboi Round 1] 限りなく灰色へ
阿巴阿巴,我是不是有什么奇奇怪怪的执念之类的东西啊。
之前是因为根号分治把我骗进来的,现在终于补习了莫反,做一下。
我怎么没有是人认证。
正文
首先是一个一个,线段上没有其他整点可以转化为 \(\gcd (|x-x_i|,|y-y_i|) = 1\)。那么就会有一个显然的 \(\mathcal O(XYn\log X)\) 的做法,直接枚举,可以有整整 \(20\) 分拿。
然后考虑把柿子写出来。
\[\max_{x=1}^X\max_{y=1}^Y \sum_{i=1}^{n} [\gcd(|x-x_i|,|y-y_i|)]
\]
显然化成。
\[\max_{x=1}^X\max_{y=1}^Y\sum_{i=1}^{n} \sum_{d|\gcd(|x-x_i|,|y-y_i|)} \mu(d)
\]
改成枚举 \(d\),\(V\) 为值域。
\[\max_{x=1}^X\max_{y=1}^Y \sum_{d}^{V} \mu(d)\sum_{i=1}^{n} [d|\gcd(|x-x_i|,|y-y_i|)]
\]
把 \(\gcd\) 拆开。
\[\max_{x=1}^X\max_{y=1}^Y \sum_{d}^{V} \mu(d)\sum_{i=1}^{n} [d||x-x_i|] [d||y-y_i|]
\]
再把整除拆开。
\[\max_{x=1}^X\max_{y=1}^Y \sum_{d}^{V} \mu(d)\sum_{i=1}^{n} [x\equiv x_i\pmod d] [y\equiv y_i\pmod d]
\]
发现可以对 \(d\) 分治,\(d\) 小则预处理 \(x_i,y_i\mod d\) 的值,\(d\) 大则暴力枚举,然后就感性认知这似乎是 \(60\) 分的做法。
但是,为什么不试着交一下呢?
AC 了。
考虑证明复杂度。
复杂度证明
不会证,算了。
考虑到不证不给过审,证明一下。
设分治边界是 \(B\)。
显然前一部分是 \(\mathcal O(n^2B)\) 的,不提。
考虑另一部分,列出来是 \(\mathcal O(n^3 \sum _{d=B}^n \frac 1{d^2})\)。
\[\begin{aligned}\sum_{d=B}^n \frac 1{d^2} &= \sum_{d=1}^n \frac 1{d^2}- \sum_{d=1}^{B-1} \frac 1{d^2} \\&\approx (\frac {\pi ^2}{6} - \frac 1n) - (\frac {\pi ^2}{6} - \frac 1{B-1}) \\&= \frac 1{B-1} - \frac 1n\\ &\approx \frac 1{B}\end{aligned}
\]
容易发现 \(B\) 取到 \(\sqrt n\) 最优,有时间复杂度 \(\mathcal O(n^2\sqrt n)\)。
讲个笑话,我最后这里没加句号又打回一次。
code
// code by 樓影沫瞬_Hz17
#include <bits/extc++.h>
using namespace std;
constexpr int N = 2010, B = 37;
int X, Y, x[N], y[N], n;
int u[N], p[N], cnp;
int vis[N];
inline void line(int n) {
u[1] = 1;
for(int i = 2; i <= n; i ++) {
if(!vis[i]) {
p[++ cnp] = i;
u[i] = -1;
}
for(int j = 1; j <= cnp and p[j] * i <= n; j ++) {
vis[p[j] * i] = 1;
if(i % p[j] == 0) {
u[i * p[j]] = 0;
break;
}
u[i * p[j]] = -u[i];
}
}
}
int me[N][N];
int sz[100][100][100];
int ans[N][N];
int su[N];
signed main() {
#ifndef ONLINE_JUDGE
freopen("in.ru", "r", stdin);
freopen("out.ru", "w", stdout);
#endif
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> X >> Y >> n;
for(int i = 1; i <= n; i ++) cin >> x[i] >> y[i], me[x[i]][y[i]] ++;
line(2000);
int csu = 0;
for(int i = 1; i <= 2000; i ++) if(u[i] != 0) su[++ csu] = i;
for(int j = 1; j <= B; j ++) {
int d = su[j];
for(int i = 1; i <= n; i ++) sz[j][x[i] % d][y[i] % d] ++;
}
for(int j = 1; j <= B; j ++) {
int d = su[j];
for(int x = 1; x <= X; x ++)
for(int y = 1; y <= Y; y ++)
ans[x][y] += (sz[j][x % d][y % d] - me[x][y]) * u[d];
}
for(int j = B + 1; j <= csu; j ++) {
int d = su[j];
for(int i = 1; i <= n; i ++) {
for(int xt = x[i] % d; xt <= X; xt += d) {
for(int yt = y[i] % d; yt <= Y; yt += d) {
if(xt == x[i] and yt == y[i]) continue;
ans[xt][yt] += u[d];
}
}
}
}
for(int i = 1; i <= n; i ++) ans[x[i]][y[i]] ++;
int as = -1;
for(int i = 1; i <= X; i ++)
for(int j = 1; j <= Y; j ++)
as = max(as, ans[i][j]);
cout << as << '\n';
}
我怎么没有是人认证。

浙公网安备 33010602011771号