4780. 【GDOI2017模拟9.14】三角形(值域分块 + 经典势能分析 + 奇妙优化)

探讨了在给定n个点的情况下,通过增加一个新点来最大化平行于坐标轴的三角形数量的问题。采用了一种高效算法,通过将新增点的代价表示为特定公式并进行分类与排序的方法,实现了O(n√n + nlogn)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem

https://jzoj.net/senior/#main/show/4780

给定 n n n个点,求新增一个点后最多能组成多少个平行于坐标轴的三角形。

Solution

实际上可以把新增一个点的代价表示为 S x ∗ S y + N u m x + N u m y Sx*Sy+Numx+Numy SxSy+Numx+Numy

那么一个经典套路是,因为 S x , S y Sx,Sy Sx,Sy的取值只有 n \sqrt{n} n 种,所以我们暂且把它分个类,并对每一种 S x Sx Sx相同的按照 N u m x Numx Numx排好序, S y Sy Sy亦然。

于是每次枚举一种 S x Sx Sx的取值,再枚举一种 S y Sy Sy的取值,然后枚举对应的 N u m x , N u m y Numx,Numy Numx,Numy,这样就具体到了某个点。

如果这个点先前不存在,那么就可以直接退出了(我们把 S y Sy Sy相同的)否则,我们就继续往下做。根据势能分析可以得知这样做的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)

由于我们至少要枚举三层,所以总的时间复杂度是 O ( n n + n l o g n ) O(n\sqrt{n}+nlogn) O(nn +nlogn)

注意,如果仅仅这么打,会T飞,但只要加上一个小小的优化,就是每次找到一个先前不存在的点后记录一下对应的 N u m y Numy Numy值在 k k k这个位置,那么以后枚举的 N u m y Numy Numy由于 N u m x Numx Numx减小的缘故,都仅仅只会到 k − 1 k-1 k1这个地方,于是就可以做到上面那个优秀的时间复杂度了(想一想,凭什么)。

Code

#include <bits/stdc++.h>

#define F(i, a, b) for (LL i = a; i <= b; i ++)

typedef long long LL;

const LL N = 2e3 + 10, K = 11;

using namespace std;

LL n, m, k, l, ans;
LL f[N][K], C[N][N], jc[N], KSM[K][2 * N * N];

int main() {
	scanf("%d%d%d%d", &n, &m, &k, &l);

	jc[0] = 1;
	F(i, 0, max(n, m) + 1)
		C[i][0] = 1;
	F(i, 1, max(n, m) + 1)
		F(j, 1, max(n, m) + 1)
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % l;
	F(i, 1, max(n, m))
		jc[i] = 1ll * jc[i - 1] * i % l;
	F(j, 1, k) {
		KSM[j][0] = 1;
		F(i, 1, 2 * n * m)
			KSM[j][i] = KSM[j][i - 1] * j % l;
	}	

	f[0][1] = 1; int w = min(n, m);
	F(i, 0, w)
		F(j, 1, k - 1)
			if (f[i][j])
				F(t, 0, w - i)
					if (n - i >= t && m - i >= t)
						f[i + t][j + 1] = (f[i + t][j + 1] + 1ll * f[i][j] * C[n - i][t] % l * C[m - i][t] % l * jc[t] % l * KSM[j][(n + m - 2 * i - t - 1) * t] % l) % l;

	F(i, 1, w)
		ans = (ans + ((i & 1) ? (1) : (- 1)) * f[i][k] * KSM[k][(n - i) * (m - i)] % l) % l;

	printf("%d\n", (ans + l) % l);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值