[ JLOI 2016 / SHOI 2016 ] 方
题目
思路
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1000010, M = 2010, S = 1e6 + 7, mod = 1e8 + 7;
int n, m, k;
// Begin Hash
int h[S], ptr[M], idx;
struct NODE { int x, y; } val[M], p[M];
inline bool find(int x, int y) {
int t = (1ll * x * 101 + y) % S;
for (int i = h[t]; i != -1; i = ptr[i])
if (val[i].x == x && val[i].y == y) return true;
return false;
}
inline void insert(int a, int b) {
int x = (1ll * a * 101 + b) % S;
val[idx] = (NODE) { a, b }, ptr[idx] = h[x], h[x] = idx++;
}
// End Hash
// Begin inv
inline int qmi(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % mod)
if (b & 1) res = 1ll * res * a % mod;
return res;
}
inline int inv(int x) { return qmi(x, mod - 2); }
// End inv
// Begin calculate
inline int calc_f0() {
int res = 0;
for (int i = 1; i <= min(n, m); i++)
res = (res + 1ll * (n - i + 1) * (m - i + 1) % mod * i % mod) % mod;
return res;
}
inline int calc(int l, int r, int h) {
int t = min(l + r, h);
if (!t) return 0;
int res = 1ll * t * (t + 3) % mod * inv(2) % mod;
if (t > l) res -= 1ll * (t - l) * (t - l + 1) % mod * inv(2) % mod;
if (t > r) res -= 1ll * (t - r) * (t - r + 1) % mod * inv(2) % mod;
return (res % mod + mod) % mod;
}
inline int calc_f1(NODE t) {
int a = n - t.x, b = m - t.y, c = t.x, d = t.y;
int res = (calc(a, c, b) + calc(a, c, d) + calc(b, d, a) + calc(b, d, c)) % mod;
res -= (min(a, b) + min(b, c) + min(c, d) + min(a, d)) % mod;
return (res % mod + mod) % mod;
}
NODE rotate(NODE a) { return { a.y, -a.x }; }
NODE operator+(NODE a, NODE b) { return { a.x + b.x, a.y + b.y }; }
NODE operator-(NODE a, NODE b) { return { a.x - b.x, a.y - b.y }; }
NODE operator/(NODE a, int b) { return { a.x / b, a.y / b }; }
inline bool inside(NODE a) { return a.x >= 0 && a.x <= n && a.y >= 0 && a.y <= m; }
inline bool check(NODE a, NODE b) { return inside(a) && inside(b); }
// 如果除以二之后都是整数, 说明在格点上
inline bool on_point(NODE a) { return ((!(a.x & 1)) && (!(a.y & 1))); }
inline int find(NODE x) { return find(x.x, x.y); }
inline int calc_f2(NODE a, NODE b) {
NODE t = rotate(a - b);
// a, b 连线作为边长的情况
int res = check(a + t, b + t) + check(a - t, b - t);
// a, b 连线作为对角线的情况
// 真正的另外两个点是 ta / 2, tb / 2
NODE mid = a + b, ta = mid + t, tb = mid - t;
if (on_point(ta) && on_point(tb) && check(ta / 2, tb / 2)) res++;
return res;
}
inline int calc_f3(NODE a, NODE b) {
NODE t = rotate(a - b);
int res = 0;
if (check(a + t, b + t)) res += find(a + t) + find(b + t);
if (check(a - t, b - t)) res += find(a - t) + find(b - t);
NODE mid = a + b, ta = mid + t, tb = mid - t;
if (on_point(ta) && on_point(tb) && check(ta / 2, tb / 2))
res += find(ta / 2) + find(tb / 2);
return res;
}
inline int calc_f4(NODE a, NODE b) {
NODE t = rotate(a - b);
int res = 0;
if (check(a + t, b + t)) res += (find(a + t) && find(b + t));
if (check(a - t, b - t)) res += (find(a - t) && find(b - t));
NODE mid = a + b, ta = mid + t, tb = mid - t;
if (on_point(ta) && on_point(tb) && check(ta / 2, tb / 2))
res += (find(ta / 2) && find(tb / 2));
return res;
}
// End calculate
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
memset(h, -1, sizeof h);
// if (n > m) swap(n, m);
for (int i = 1; i <= k; i++)
cin >> p[i].x >> p[i].y, insert(p[i].x, p[i].y);
int f0 = calc_f0(), f1 = 0, f2 = 0, f3 = 0, f4 = 0;
for (int i = 1; i <= k; i++)
f1 = (f1 + calc_f1(p[i])) % mod;
for (int i = 1; i <= k; i++) {
for (int j = i + 1; j <= k; j++) {
f2 = (f2 + calc_f2(p[i], p[j])) % mod;
f3 = (f3 + calc_f3(p[i], p[j])) % mod;
f4 = (f4 + calc_f4(p[i], p[j])) % mod;
}
}
f3 = 1ll * f3 * inv(3) % mod, f4 = 1ll * f4 * inv(6) % mod;
int res = ((f0 - f1 + f2 - f3 + f4) % mod + mod) % mod;
cout << res << endl;
return 0;
}