C. Maximize the Intersections

C. Maximize the Intersections

[link](Problem - C - Codeforces)

题意

在一个圆上有2n个不同的点,具有以下性质:无论你如何选择3条连接3个互不相干的点的弦,在圆内没有一个点严格属于所有3条弦。这些点按顺时针顺序被编号为1,2,…,2n。

最初,k条和弦连接了k对点,其方式是这些和弦的所有2k个端点是不同的。

你想画出n-k条额外的和弦,连接剩余的2(n-k)个点(每个点必须正好是一个和弦的端点)。

最后,让x成为所有n条弦的交叉点的总数。计算如果你以最佳方式选择n-k条弦,x能达到的最大值。

请注意,2n个点的确切位置并不重要,只要第一段中所述的属性成立即可。

题解

首先对于两条弦是否相交如何判断?

假设x1 < y1, x2 < y2且x1 < x2则当且仅当 x2 < y1 && y1 < y2时两弦有交点

什么情况下交点数最多?

假设有2n个点,从 1 - n + 1连一条边,这个弦的两侧的点数相同,弦的左右的点两两配对,则其余点对于该弦的贡献就是n - 1,因此,我们将所有的点按照 i - i + n 这种形式排列好,那么每一条弦的贡献一定都是n - 1,因为一共2n个点,n个弦,每个弦最多贡献是n - 1所以这种情况一定是最优的,因此,把剩下的没连过的点按照相对顺序依照这种方法连接即可。然后暴力跑一遍一否成立即可。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip> 
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 5e4 + 10, M = 30010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m;

bool check(PII c, PII d) { // 判断是否有交点 
	if (c.x > d.x) swap(c, d); // c靠前 
	return c.y < d.y &&  d.x < c.y;
}
int main () {
	cin.tie(nullptr)->sync_with_stdio(false);
	int T;
	cin >> T;
	while (T --) {
			cin >> n >> m; // n条弦和用了m条 
			vector<PII> chords; // 存所有弦的xi,yi 
			vector<bool> used(2 * n + 1, false); // 判断哪些弦题目中给了 
			for (int i = 1; i <= m; i ++ ) {
				int x, y;
				cin >> x >> y;
				if (x > y) swap(x, y); // 从小到大 定序 方便后面操作 
				chords.push_back({x, y});  // 将弦加入 
				used[x] = used[y] = true; // 表示用过了 
			}
			vector<int> unused; // 存没用过的弦 
			for (int i = 1; i <= 2 * n; i ++ )
				if (!used[i]) unused.push_back(i); // 找到所有没用过的弦 
			for (int i = 0; i < n - m; i ++ )  // 将所有没用过的弦按照相对顺序,依照最优策略连弦 
				chords.push_back({unused[i], unused[i + n - m]}); // 加入到方案内 
			int res = 0;
			for (int i = 0; i < n; i ++ )  // 暴力枚举 
				for (int j = i + 1; j < n; j ++ )
					res += check(chords[i], chords[j]); // 是否合理 
			cout << res << endl;
		}
	 return 0;
}



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值