1. 程式人生 > 其它 >【題解】CF1764C Doremy's City Construction

【題解】CF1764C Doremy's City Construction

題目傳送門

思路

首先我們思考一個性質,由於不能有連續單調不升/不降的三個點連在一起,所以對於單個點來講,顯然要麼只和比它大的連邊(稱為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;
}