【題解】CF1764C Doremy's City Construction
阿新 • • 發佈:2022-12-11
題目傳送門
思路
首先我們思考一個性質,由於不能有連續單調不升/不降的三個點連在一起,所以對於單個點來講,顯然要麼只和比它大的連邊(稱為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; }