• [做题记录计数] [THUPC2021 初赛] 方格游戏 HN


    题意

    小 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模拟赛里面的我就没对过

    纪念第一个自己推出来的分类讨论, 虽然好像并没有什么难度

    考虑先不考虑障碍物直接求每两两之间不考虑障碍物的最短路, 然后减去障碍物里面到外面的, 然后加上绕路的部分, 一点一点讨论。

    不考虑障碍物的两两最短路之和

    考虑对于横坐标和纵坐标分别枚举长度计算贡献得到 :

    \[\sum_{i = 0}^{n - 1}m^2(n -i)i + \sum_{i = 0}^{m - 1}n^2(m - i)i = \frac{m^2(n^3 - n) + n^2(m^3 - m)}{6} \]

    计算障碍物内外的最短路之和

    只考虑当前一个障碍物, 当前障碍物为 \((l_x, r_x, l_y, r_y)\) 分别表示横纵坐标。

    先考虑横坐标的贡献, 记 \(S1(n) = \sum_{i = 1}^ni\), \(S2 = \sum_{i = 1}^ni^2\)

    \[\sum_{i = l_x} ^{r_x}\sum_{j = 1}^n|j - i|m(r_y - l_y + 1) \]

    \(m(r_y - l_y + 1) = C\) 最后乘上。

    \[\sum_{i = l_x} ^{r_x}\sum_{j = 1}^n|j - i| \\ = \sum_{i = l_x}^{r_x}\sum_{j = 1}^{i - 1} i - j + \sum_{i = l_x}^{r_x}\sum_{j = i +1}^{n} j - i \\ = \sum_{i = l_x}^{r_x}i(i - 1) - \sum_{i = l_x} ^ {r_x} \frac{i(i - 1)}{2} - \sum_{i = l_x}^{r_x}(n - i)i + \sum_{i = l_x}^{r_x}\frac{(n - i)(i + 1 + n)}{2} \\ = \frac{1}{2} \times \sum_{i = l_x}^{r_x} 2i^2 - 2in +n^2 + n - 2i \]

    所以 \(x\) 轴的贡献是 :

    \[\frac{1}{2} \times C \times [(r_x - l_x + 1) \times (n^2 + n) + 2 (S2(r_x) - S2(l_x - 1)) - (2n + 2)(S1(r_x) - S1(l_x - 1))] \]

    同理 \(y\) 轴的贡献就是 :

    \[\frac{1}{2} \times C \times [(r_y - l_y + 1) \times (m^2 + m) + 2 (S2(r_y) - S2(l_y - 1)) - (2m + 2)(S1(r_y) - S1(l_y - 1))] \]

    计算障碍物到自己里面的最短路之和

    就是一开始的计算全局不考虑障碍物的路径长度之和的做法。

    计算当前障碍物里面到外面所有障碍物路径之和

    有一个经典的操作。

    同样把 \(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\) 。可以写出答案 :

    \[\sum_{i = 1}^l\sum_{j = 1}^l2\times \min(i, l - i + 1, j, l - j + 1) \]

    不妨设 \(l\) 为偶数, \(t = \frac{l}{2}\)

    \[\sum_{i = 1}^l\sum_{j = 1}^l2\times \min(i, l - i + 1, j, l - j + 1) \\ =4\times \sum_{i = 1}^t\sum_{j = 1}^t2 \min (i, j) \\ = 4\times ((2t + 1)\frac{t(t+ 1)}{2} - \frac{t(t + 1)(2t + 1)}{6}) \]

    考虑 \(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;
    }
  • 相关阅读:
    什么是Flex 布局
    wx.navigateTo、wx.redirectTo和wx.switchTab三种导航方式的区别
    Ajax 工作原理 及 实例
    NodeJS之 Express框架 app.use(express.static)
    Parcel 入门 (一)
    打包工具的介绍
    CSS网页布局
    《拖延心理学》阅读要点
    PHP实现页面静态化
    PHP中的魔术方法
  • 原文地址:https://www.cnblogs.com/clover4/p/15717221.html
Copyright © 2020-2023  润新知