题意

给定一个方格图,每个点上都有一个值$p_{i,j}$,两个格子之间的距离d被定义为格点中心的欧氏距离,现在给出一个分数的定义,每个格点的分数被定义为所有距离在r以内的格点的p/(d+1)的值,求得分最大的格点的分数

解题思路

基本做法是求解每个格点的分数,然后得到其中的最大值

所以对于每个$i$,需要求出$\sum_{d<r}(\frac{p_{x_i-d_x,y_i-d_y}}{\sqrt{d_x^2+d_y^2}+1})$

所有需要对点$i$产生贡献的点$j$的坐标和偏移量$d$满足$x_j+d_x=x_i$,$y_j+d_y=y_i$

构造$A_{i∗M+j}=p_{i,j}$,$B_{d_x * M + d_y} = \frac{1}{\sqrt{d_x^2+d_y^2} +1}$

对于条件距离$r$可以在$B$的赋值时做判断处理

考虑到$d_x$和$d_y$的取值范围为$[R,-R]$,我们对偏移量做偏移处理

即$B_{(i + R) * M + j + R} = \frac{1}{\sqrt{i ^ 2 + j ^ 2} +1}$

则$A$和$B$的卷积$C_{(i + R) * M + j + R}$即格点$(i,j)$的得分

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <bits/stdc++.h>
using namespace std;
const int N = 2097152;
int pos[N];
namespace FFT {
struct comp {
double r, i;
comp(double _r = 0, double _i = 0) : r(_r), i(_i) {}
comp operator+(const comp &x) { return comp(r + x.r, i + x.i); }
comp operator-(const comp &x) { return comp(r - x.r, i - x.i); }
comp operator*(const comp &x) {
return comp(r * x.r - i * x.i, i * x.r + r * x.i);
}
comp conj() { return comp(r, -i); }
};
const double pi = acos(-1.0);
void FFT(comp a[], int n, int t) {
for (int i = 1; i < n; i++)
if (pos[i] > i) swap(a[i], a[pos[i]]);
for (int d = 0; (1 << d) < n; d++) {
int m = 1 << d, m2 = m << 1;
double o = pi * 2 / m2 * t;
comp _w(cos(o), sin(o));
for (int i = 0; i < n; i += m2) {
comp w(1, 0);
for (int j = 0; j < m; j++) {
comp &A = a[i + j + m], &B = a[i + j], t = w * A;
A = B - t;
B = B + t;
w = w * _w;
}
}
}
if (t == -1)
for (int i = 0; i < n; i++) a[i].r /= n;
}
} // namespace FFT
FFT::comp A[N], B[N];
int main() {
int n, m, x;
double r;
while (~scanf("%d%d%lf", &n, &m, &r)) {
int R = ceil(r), M = max(n + 2 * R, m + 2 * R);
int N = 1;
while (N < M * M) N <<= 1;
for (int i = 0; i < N; i++) A[i] = B[i] = FFT::comp(0, 0);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
scanf("%d", &x);
A[i * M + j] = FFT::comp(x, 0);
}
auto dis = [](int x, int y) { return sqrt(x * x + y * y); };
for (int i = -R; i <= R; i++) {
for (int j = -R; j <= R; j++) {
if (dis(i, j) < r)
B[(i + R) * M + j + R] =
FFT::comp(1.0 / (dis(i, j) + 1), 0);
}
}
int j = __builtin_ctz(N) - 1;
for (int i = 0; i < N; i++) {
pos[i] = pos[i >> 1] >> 1 | ((i & 1) << j);
}
FFT::FFT(A, N, 1);
FFT::FFT(B, N, 1);
for (int i = 0; i < N; i++) A[i] = A[i] * B[i];
FFT::FFT(A, N, -1);
double ans = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
ans = max(ans, A[(i + R) * M + j + R].r);
printf("%.3f\n", ans);
}
return 0;
}