题意
小 F 和小 H 在玩游戏。今天,他们在一个 \(N \times M\) 的棋盘上玩游戏。小 H 想考考小 F 的数学能力,但小 F 天生数学就不好,所以想请你帮忙。
为了加大难度,小 H 会在棋盘里面加入 \(P\) 个矩形障碍物。每个矩形障碍物用 \(U\)、\(D\)、\(L\)、\(R\) 来表示,即在第 \(U\) 行到第 \(D\) 行以及在第 \(L\) 列到第 \(R\) 列之间的所有格子都变成了障碍物。小 H 保证所有矩形障碍物互不相交,并且所有非障碍物格子之间都能够直接或者间接互达,若两个非障碍物格子有公共边,那么它们直接互达并且它们的距离为 1 。
现在每一局游戏中,小 F 在棋盘中挑选一个非障碍物格子 \(X\),小 H 也挑另外一个非障碍物格子 \(Y\),这一局游戏 \((X,Y)\) 的得分就是 X 到 Y 的最短路径。小 F 需要计算出所有可能的游戏中的得分和,答案模 \(1,000,000,007\)。
注意两局游戏中只要挑选的两个格子相同则视为同一局游戏,即 \((X, Y)\) 等同于 \((Y, X)\)。
第一行三个整数 \(N(1 \leq N \leq 1,000,000,000)\),\(M(1 \leq M \leq 1,000,000,000)\),\(P(0 \leq P \leq 100,000)\)。
接下来有 \(P\) 行,每行四个正整数,\(U_i\),\(D_i (1<U_i \leq D_i<N)\),\(L_i\),\(R_i(1<L_i \leq R_i<M)\),表示第 \(i\) 个矩形障碍物。
对于任意两个不同的矩形障碍物 \(i\) 和 \(j\),都满足 \(D_i+1<U_j\) 或者 \(D_j+1<U_i\),以及 \(R_i+1<L_j\) 或者 \(R_j+1<L_i\)。
只有一行一个正整数,即所有游戏的得分和模 \(1,000,000,007\)。
距离为 1 的有 8 种。
距离为 2 的有 8 种。
距离为 3 的有 8 种。
距离为 4 的有 4 种。
总共得分为 64 。
题解
分类讨论题。 终于见到阳间的分类讨论题了, md模拟赛里面的我就没对过 。
纪念第一个自己推出来的分类讨论, 虽然好像并没有什么难度
考虑先不考虑障碍物直接求每两两之间不考虑障碍物的最短路, 然后减去障碍物里面到外面的, 然后加上绕路的部分, 一点一点讨论。
不考虑障碍物的两两最短路之和
考虑对于横坐标和纵坐标分别枚举长度计算贡献得到 :
计算障碍物内外的最短路之和
只考虑当前一个障碍物, 当前障碍物为 \((l_x, r_x, l_y, r_y)\) 分别表示横纵坐标。
先考虑横坐标的贡献, 记 \(S1(n) = \sum_{i = 1}^ni\), \(S2 = \sum_{i = 1}^ni^2\)
令 \(m(r_y - l_y + 1) = C\) 最后乘上。
所以 \(x\) 轴的贡献是 :
同理 \(y\) 轴的贡献就是 :
计算障碍物到自己里面的最短路之和
就是一开始的计算全局不考虑障碍物的路径长度之和的做法。
计算当前障碍物里面到外面所有障碍物路径之和
有一个经典的操作。
同样把 \(x\) 轴和 \(y\) 轴分开考虑, 以 \(x\) 轴为例。
我们把矩形按照 \(x\) 轴排序, 维护之前的点数和 \(cnt\) 以及 \(x\) 坐标和 \(sum_x\),记当前障碍的点数为 \(c\), 当前的障碍的 \(x\) 坐标和是 \(s\) 。
把答案加上 \(cnt \times s - sum_x\times c\) 即可。
计算绕远路的部分
同样不妨考虑 \(x\) 轴的贡献, 设障碍物的宽为 \(l\) , 左边有 \(L\) 个数, 右边有 \(R\) 个数, \(C = L \times R\) 。可以写出答案 :
不妨设 \(l\) 为偶数, \(t = \frac{l}{2}\) 。
考虑 \(l\) 是奇数的情况, 只要加一个 \((l +1)^2\times \frac{1}{2}\) 即可, 具体只要观察一下会多出来哪些东西就好了。
#include <bits/stdc++.h>
using namespace std;
#define lep(i, l, r) for(int i = (l); i <= (r); i ++)
#define rep(i, l, r) for(int i = (l); i >= (r); i --)
#define Lep(i, l, r) for(int i = (l); i < (r); i ++)
#define Rep(i, l, r) for(int i = (l - 1); i >= (r); i --)
#define debug(...) fprintf (stderr, __VA_ARGS__)
#define pb push_back
#define fi first
#define se second
#define gc getchar
#define pc putchar
using i64 = long long;
using uint = unsigned int;
using ui64 = unsigned long long;
using pii = std :: pair<int, int>;
using vi = std :: vector<int>;
template<typename A, typename B>
inline void Min(A &x, B y) { x = x < y ? x : y; }
template<typename A, typename B>
inline void Max(A &x, B y) { x = x > y ? x : y; }
template<typename T> inline void read(T &x) {
x = 0; char a = gc(); bool f = 0;
for (; ! isdigit(a); a = gc()) if (a == '-') f = 1;
for (; isdigit(a); a = gc()) x = x * 10 + a - '0';
if (f) x = -x;
}
const int P = 1e9 + 7;
inline int mod(int x) { return x + (x >> 31 & P); }
inline void sub(int &x, int y) { x = mod(x - y); }
inline void pls(int &x, int y) { x = mod(x + y - P); }
inline int add(int x, int y) { return mod(x + y - P); }
inline int dec(int x, int y) { return mod(x - y); }
inline int power(int x, i64 k) {
int res = 1; if (k < 0) k += P - 1;
while (k) { if (k & 1) res = 1ll * res * x % P; x = 1ll * x * x % P; k >>= 1; }
return res;
}
const int inv2 = power(2, P - 2);
const int inv6 = power(6, P - 2);
const int N = 1e5 + 10;
struct Node {
int lx, rx, ly, ry;
} o[N];
inline int calc1(int n, int m) {
int x = 1ll * m * m % P * (1ll * n * n % P * n % P - n + P) % P;
int y = 1ll * n * n % P * (1ll * m * m % P * m % P - m + P) % P;
pls(x, y); return 1ll * x * inv6 % P;
}
inline int S1(int n) {
return 1ll * n * (n + 1) % P * inv2 % P;
}
inline int S2(int n) {
return 1ll * n * (n + 1) % P * (n * 2 + 1) % P * inv6 % P;
}
inline int calc2(int lx, int rx, int ly, int ry, int n, int m) {
int C, a, b, c, r1 = 0, r2 = 0;
C = 1ll * inv2 * m % P * (ry - ly + 1) % P;
a = 1ll * (rx - lx + 1) * (1ll * n * n % P + n) % P;
b = 2ll * (S2(rx) - S2(lx - 1) + P) % P;
c = 1ll * (2 * n + 2) * (S1(rx) - S1(lx - 1) + P) % P;
pls(r1, a); pls(r1, b); sub(r1, c); r1 = 1ll * r1 * C % P;
swap(lx, ly); swap(rx, ry); swap(n, m);
C = 1ll * inv2 * m % P * (ry - ly + 1) % P;
a = 1ll * (rx - lx + 1) * (1ll * n * n % P + n) % P;
b = 2ll * (S2(rx) - S2(lx - 1) + P) % P;
c = 1ll * (2 * n + 2) * (S1(rx) - S1(lx - 1) + P) % P;
pls(r2, a); pls(r2, b); sub(r2, c); r2 = 1ll * r2 * C % P;
return add(r1, r2);
}
inline int _calc3(int L, int R, int l) {
int t = l / 2;
int x = 1ll * (l + 1) * t % P * (t + 1) % P * inv2 % P;
int y = S2(t);
int r = dec(x, y); r = 1ll * r * 4 % P;
if(l & 1)
pls(r, 1ll * (l + 1) * (l + 1) % P * inv2 % P);
return 1ll * r * L % P * R % P;
}
inline int calc3(int lx, int rx, int ly, int ry, int n, int m) {
int ans = 0;
pls(ans, _calc3(lx - 1, n - rx, ry - ly + 1));
pls(ans, _calc3(ly - 1, m - ry, rx - lx + 1));
return ans;
}
int n, m, q;
int Ans;
int main() {
read(n); read(m); read(q);
Ans = calc1(n, m);
lep (i, 1, q) {
int lx, rx, ly, ry;
read(lx); read(rx); read(ly); read(ry);
o[i] = {lx, rx, ly, ry};
sub(Ans, calc2(lx, rx, ly, ry, n, m));
pls(Ans, calc3(lx, rx, ly, ry, n, m));
pls(Ans, calc1(rx - lx + 1, ry - ly + 1));
}
int sum, cnt;
sum = 0; cnt = 0;
sort(o + 1, o + 1 + q, [] (Node a, Node b) { return a.lx < b.lx; } );
lep (i, 1, q) {
int c = 1ll * (o[i].rx - o[i].lx + 1) * (o[i].ry - o[i].ly + 1) % P;
int s = 1ll * (o[i].lx + o[i].rx) * (o[i].rx - o[i].lx + 1) % P * inv2 % P * (o[i].ry - o[i].ly + 1) % P;
pls(Ans, (1ll * s * cnt % P - 1ll * c * sum % P + P) % P);
pls(sum, s);
pls(cnt, c);
}
lep (i, 1, q) swap(o[i].lx, o[i].ly), swap(o[i].rx, o[i].ry);
sum = 0; cnt = 0;
sort(o + 1, o + 1 + q, [] (Node a, Node b) { return a.lx < b.lx; } );
lep (i, 1, q) {
int c = 1ll * (o[i].rx - o[i].lx + 1) * (o[i].ry - o[i].ly + 1) % P;
int s = 1ll * (o[i].lx + o[i].rx) * (o[i].rx - o[i].lx + 1) % P * inv2 % P * (o[i].ry - o[i].ly + 1) % P;
pls(Ans, (1ll * s * cnt % P - 1ll * c * sum % P + P) % P);
pls(sum, s);
pls(cnt, c);
}
printf("%d\n", Ans);
return 0;
}