P14988 多边形 个人题解
题目大意
给定 \(n\) 根木棍,问从这些木棍中选取 \(k\)(\(3\le k \le n\))根木棍,能否拼凑出一个面积不为 \(0\) 的 \(k\) 边形。
Solution
大家在初中甚至小学的时候就应该学到过三角形的三边关系,那就是两边之和大于最长的第三边,同理对于这道题的 \(k\) 边形也适用,原因就是当 \(k-1\) 边之和等于最长的第 \(k\) 边时,这个 \(k\) 边形刚好是一条直线,所以只要这 \(k-1\) 边之和大于最长的第 \(k\) 边,这个 \(k\) 边形的面积就一定不为 \(0\)。
那么我们可以将这 \(n\) 根木棍从小到大排序,依次从这些木棍中选出相邻的 \(k\) 根木棍,判断最长那根的长度是否比其他的木棍长度和小,如果是直接退出循环就好了。为什么要取相邻的木棍呢?因为相邻的木棍之间的长度差一定是最小的,那么补足这些长度差所需要的木棍长度就是最少的,能构成 \(k\) 边形的几率就是最大的。然后由于我们不能每一次都去算这 \(k-1\) 根木棍的和,所以我们在排完序之后做一个前缀和,这样就能快速求出这 \(k-1\) 根木棍的和,然后去与第 \(k\) 根木棍长度作比较。
代码
#include<bits/stdc++.h>
#define int long long//不开long long见祖宗
using namespace std;
const int N=2e5+6;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0' && c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int n=read(),a[N],s[N];
signed main(){
for(int i=1;i<=n;i++)
a[i]=read();
sort(a+1,a+n+1);//从小到大排序
for(int i=1;i<=n;i++)//做一遍前缀和
s[i]=s[i-1]+a[i];
for(int k=3;k<=n;k++){//枚举构成的k边形
bool ok=false;
for(int l=1,r=k;r<=n && !ok;l++,r++){
int x=s[r-1]-s[l-1];//k-1根木棍的和
if(x>a[r]) ok=true;//如果满足和大于最长边的长度,直接记录跳出循环
}
if(ok) printf("%lld ",k);
}
return 0;
}

浙公网安备 33010602011771号