题目传送门
思路
首先我们思考一个性质,由于不能有连续单调不升/不降的三个点连在一起,所以对于单个点来讲,显然要么只和比它大的连边(称为A类点),要么只和比它小的连边(称为B类点),要么只和与自己一样大的连边(称为C类点),要么不连边(称为D类点)
首先D类点肯定是极力避免的,其次C类点能且仅能连一条边(显然可知),所以我们要优先考虑A类点和B类点
我们先假设所有点都是A类点或者B类点,那么排序后显然A类点可以和权值比该点大的所有B类点连边,反之亦然
我们发现,如果A类点和B类点的数量已知,那么显然让A类点的权值尽可能小、B类点的权值尽可能大最优
这样,问题就变成了对转化后的数组找分界线的问题
根据简单的均值不等式,容易得出分界线落在 \(\lfloor\frac{n}{2}\rfloor\) 是最优的
然而,如果分界线左右的点的权值相等,显然会变成C类点,就不能这么计算答案了
所以,实际上我们要把权值相等的数缩为一个数,然后再寻找分界线
当然,由于排序复杂度就为 \(O(n\log n)\) 了,所以无需优化枚举复杂度,暴力找即可
不过,如果所有点的权值都相等,那么就要尽可能地增多C类点了,这时答案为 \(\lfloor\frac{n}{2}\rfloor\)
总复杂度为排序复杂度,可以通过此题
代码
//吾日九省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
//多测清空不彻底乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
const ll nanhenhenaaaaaaaaaaa(-1145141919810);
ll T,n,ans;
ll num[5000233];
ll stk[5000233],top,numeral;
ll sum;
int main(){
cin>>T;
while(T--){
cin>>n;ans=n>>1;
sum=0;
for(ll i=1;i<=n;++i){
cin>>num[i];
stk[i]=0;
}
sort(num+1,num+n+1);
numeral=nanhenhenaaaaaaaaaaa;
top=0;
for(ll i=1;i<=n;++i){
if(numeral!=num[i]){
numeral=num[i];
stk[++top]++;
}
else stk[top]++;
}
for(ll i=0;i<=top;++i){
sum+=stk[i];
ans=max(ans,sum*(n-sum));
}
cout<<ans<<endl;
}
return 0;
}
标签:City,num,题解,类点,Construction,复杂度,权值,include,ll
From: https://www.cnblogs.com/Konjac-Binaries/p/16973910.html