专栏文章

题解:P12804 [AMPPZ 2019] Polygon

P12804题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minqk1lh
此快照首次捕获于
2025/12/02 06:43
3 个月前
此快照最后确认于
2025/12/02 06:43
3 个月前
查看原文

简化

仔细想想可以发现:一个凹多边形可以把凹进去的两条边不改变长度的情况下翻转出来,重复此操作可以让凹多边形变成凸的。
所以题目可以简化成求构造出的多边形可能的最大周长。

再简化

怎么判断一些线段是否可以连成多边形呢?
有一个性质:多边形的任意一个边一定小于于其他边的和。
在把问题化成:给定一个序列,求出里面和最大的子序列,子序列的任意一个值小于子序列的其他值的和。

证明

反证法。
假设有一个多边形,有一条边的长度大于其他边的和。这条边的两个端点是 xxyy
xxyy 有两条路径,一条是这条“特殊边”,另一条是其他边。这条边是直的。另一条路径上有其他端点,所以不是直的。
两点之间直线最短,所以这条边的长度小于其他边的和。与原假设矛盾。

实现

把这些边从小到大排序。可以发现答案是原来序列的前缀。

证明

因为从小到大排序了。从前往后选择的时候,如果一个值大于前面所有值的和了。那么也不能选择后面的值了,因为后面的值比这个值还要大。

由于要最大的周长,排序之后从后往前遍历,也就是从最大的前缀开始枚举。如果这个前缀满足最小值小于其他值的和,那么它可以围成多边形,那么输出这个前缀的和。
因为一个前缀的最小值是最后一个值,其他值就是长度比它小一的前缀。所以其他值的和就是前缀和。可以预处理出前缀和来优化。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
long long a[100010];
long long sum[100010];
void f(){
	long long n;
	cin>>n;
	for(long long i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n);
	sum[0]=a[0];
	for(long long i=1;i<n;i++){
		sum[i]=sum[i-1]+a[i];
	}
	for(long long i=n-1;i>=2;i--){
		if(a[i]<sum[i-1]){
			cout<<sum[i]<<endl;
			return;
		}
	}
	cout<<"0\n";
}
int main(){
	long long T;
	cin>>T;
	while(T--){
		f();
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...