题解 UVa11139

题目大意 多组数据,每组数据给定一个正整数 \(n(n\leq 120)\),要求输出在 \(n\times n\) 的网格中(即 \((n+1)\times(n+1)\) 的格点中)有多少个不同的四边形。

分析 这道毒瘤题卡了我半个月,本篇题解将记录下我思考的过程。

仔细分析题目中的四边形,发现是凸四边形与凹四边形的总和,所以考虑用点集来代替四边形。如果四个点构成凸四边形,则其贡献为一;如果构成凹四边形,则其贡献为三,这是因为每个凹四边形都可以看作是一个三角形和其中的一个点。那么我们可以统计所有的可以构成四边形的不同四元点对的数目,然后再加上两倍凹四边形点集的个数。前面那一个的求法与 题解 LA3295 的求法类似,可以先预处理三点共线和四点共线的数量,然后 \(O(1)\) 求,这里不再赘述。接下来我们讨论如何求凹四边形的个数。

\(n\leq 120\) 说明我们最多只能用 \(O(n^4)\) 的方法求。最容易想到的就是 \(O(n^8)\) 枚举每个四边形再查找,这显然是不行的,我们考虑优化。注意到凹四边形的等价表述:一个三角形和其内部的一个点。再注意到这是个格点的问题,不难想到使用 Pick 定理(即不自相交格点多边形的面积为内部格点的个数加上边上的格点个数的一半减一)来计算。事实上,如果我们知道三个点 \(A(x_A,y_A),B(x_B,y_B),C(x_C,y_C)\),则

\[S_{\triangle ABC}=\frac12|(x_Ay_B+x_By_C+x_Cy_A)-(y_Ax_B+y_Bx_C+y_Cx_A)| \]

且有 \(AB\) 间的点的个数(不含端点)为

\[gcd(|x_A-x_B|,|y_A-y_B|)-1 \]

也就是说如果我们枚举每个三角形,则可以 \(O(1)\) 地(近似,因为 \(gcd\) 函数也有复杂度)算出这个三角形内部包含的点的个数,亦即凹四边形的个数,这样的复杂度是 \(O(n^6)\),还需要进一步优化。

仔细考虑会发现所有的格点三角形可以分为许多部分,其中每一部分是全等的,所以我们尝试枚举不同的类别。具体来说,我们先把三角形三个顶点按照横坐标排序,把最左边的顶点看作是原点,重新建立坐标系。即如果 \(A(0,0)\),则有 \(B(\Delta x_1, \Delta y_1),C(\Delta x_2, \Delta y_2)\),其中 \(\Delta x_1=x_B-x_A, \Delta y_1=y_B-y_A, \Delta x_2=x_C-x_A, \Delta y_2=y_C-y_A\),那么有 \(0\leq\Delta x_1\leq\Delta x_2\leq n,-n\leq\Delta y_1,\Delta y_2\leq n\),且 \(max\{|\Delta y_1|, |\Delta y_2|, |\Delta y_1 - \Delta y_2|\}\leq n\)。那么我们可以直接枚举 \(B,C\)\(A\) 的相对坐标,用它的贡献乘以其在网格内出现的次数。这样做是 \(O(n^4)\) 的。

事实上,用上述方法跑得特别慢,所以实际应用中可以打表做出凹四边形的个数。

打表:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 125;

inline ll llabs(ll x)
{
	return x > 0 ? x : -x;
}

inline ll gcd(ll a, ll b)
{
	return !b ? a : gcd(b, a % b);
}

ll concave(ll n)
{
	ll S_2, a, b, ans = 0;
	
	for(register ll x1 = 1; x1 <= n; ++x1) {
		for(register ll y1 = -n; y1 <= n; ++y1) {
			for(register ll x2 = x1; x2 <= n; ++x2) {
				for(register ll y2 = -n; y2 <= n; ++y2) {
					if(x1 * y2 == x2 * y1) continue;
					
					ll maxy = max(llabs(y1), max(llabs(y2), llabs(y1 - y2)));
					if(maxy > n) continue;
					
					S_2 = abs(x1 * y2 - x2 * y1);
					b = __gcd(x1, llabs(y1)) + __gcd(x2, llabs(y2)) + __gcd(x2 - x1, llabs(y2 - y1));
					a = (S_2 - b) / 2 + 1;
					ans += 3 * a * (n - x2 + 1) * (n - maxy + 1);
				}
			}
		}
	}
	
	return ans;
}

int main()
{
	freopen("test.out", "w", stdout);
	for(int i = 1; i <= 120; ++i)
		printf("%lld, ", concave(i));
}

程序:

#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
const int maxn = 125;

ull dp3[maxn][maxn], dp4[maxn][maxn];
ull concave[121] = { 0, 0, 24, 720, 6300, 34812, 135552, 436944, 1198968, 2929656, 6516984, 13502448, 26208516, 48407988, 85481280, 145200888, 238502808, 380729160, 591761304, 899049096, 1336994100, 1950873276, 2798226336, 3952174032, 5500597632, 7555866072, 10253438688, 13757838288, 18265978212, 24018852948, 31292948904, 40428444480, 51813846552, 65909234160, 83250558000, 104455928568, 130233266532, 161419027572, 198951059448, 243902817024, 297486114576, 361107057912, 436308159048, 524880044160, 628787352876, 750245801604, 891755031048, 1056101842512, 1246322048784, 1465872593064, 1718522294664, 2008472374680, 2340330988092, 2719232119716, 3150709026432, 3640923976560, 4196561834712, 4825013412408, 5534317745952, 6333266701776, 7231232496324, 8238727186932, 9366959680872, 10628053027680, 12035213048784, 13602734553456, 15345951409392, 17281654340496, 19427648992380, 21803261472804, 24429099279144, 27327660798360, 30522542402856, 34039679008656, 37906442531784, 42152066923224, 46807974815700, 51907724212884, 57486945914352, 63584110589760, 70239451395096, 77496434453664, 85401182057544, 94002772569456, 103352546741556, 113506039376796, 124521839447568, 136461906737304, 149391640644144, 163381072173408, 178502895530016, 194835361228224, 212460527856348, 231465258605820, 251941158008760, 273984631414848, 297696810145488, 323185867420848, 350564120524848, 379950211335696, 411468807779412, 445252228438140, 481437580613304, 520170764300112, 561602983331856, 605893561191744, 653210886995592, 703730932707096, 757636028786508, 815120490647004, 876384679144704, 941640503975520, 1011107706346608, 1085018919884880, 1163614105147320, 1247146130025864, 1335878192594796, 1430084981069604, 1530054397164024, 1636085561645640, 1748488311799128 };

ull C(ull n, ull m)
{
	if(m > n) return 0;
	
	ull res = 1;
	for(ull i = 1; i <= m; ++i)
		res = res * (n - i + 1) / i;
	return res;
}

void Init(int n)
{
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			dp3[i][j] = dp3[i - 1][j] + dp3[i][j - 1] - dp3[i - 1][j - 1] + __gcd(i, j) - 1,
			dp4[i][j] = dp4[i - 1][j] + dp4[i][j - 1] - dp4[i - 1][j - 1] + C(__gcd(i, j) - 1, 2);
	
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			dp3[i][j] += dp3[i - 1][j] + dp3[i][j - 1] - dp3[i - 1][j - 1],
			dp4[i][j] += dp4[i - 1][j] + dp4[i][j - 1] - dp4[i - 1][j - 1];
}

ull all(ull n)
{
	ull tot = (n + 1) * (n + 1);
	return C(tot, 4) - 2 * (dp3[n][n] * (tot - 3) - 3 * dp4[n][n]) - 2 * (n + 1) * (C(n + 1, 3) * (tot - 3) - 3 * C(n + 1, 4));
}

int main()
{
	Init(120);
	
	ull n;
	while(cin >> n && n) {
		cout << n << " " << all(n) + concave[n] / 3 * 2 << endl;
	}
}
posted @ 2020-02-10 22:48  whx1003  阅读(264)  评论(0编辑  收藏  举报