链接:https://codeforces.com/problemset/problem/1682/C
题意: 时间1秒 范围
输入t组 长度为n的数列a。
求该数列的LIS(a) 和 LIS(a’) a'为数组a的翻转
求出 temp = min(LIS(a),LIS(a’) )
数列可以经过任意排列, 使这个temp 最大
思路:
通过输入的情况可以看到,最大大概是 2*10^9
我们处理起来也就是 10^4 * (2*10^5 * 算法)
考虑 n 和 sqrt(n) 的算法
这样来看全排列应该是不能暴力的,找最长上升子序列是nlogn也不能用
算法最多就是搜一遍
通过题意我们可以看出,如果我们想使temp 最大,那么严格最长上升子序列和严格最长下降子序列应该尽量保持一致
假设出现的每一个数的次数都>=2,那么我们将两边排开 可以使两边的数量一致,剩下的数随便扔到两边
也就是说,如果对于任意cnt(ai) >=2 ,那么 temp = set(a).size()
然后考虑单数情况,如果看出了上面的规律,这里我们不难考虑。如果一堆数出现的次数都是1,也就是他们互不相同。我们从中间开始,依次向两边放入两个剩下数中最大的数,cnt 为单数 ,temp = cnt/2向上取整
将两种情况合并就是最终答案
使用mapt记录 每个数出现的次数,然后用迭代器遍历一遍。这个复杂度在n以内
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long map<ll,ll>mapt; int main() { ll t ,n; cin>>t; while(t--) { ll k,cnt2=0,dcnt=0; cin>>n; for(ll i=1;i<=n;i++) { cin>>k; mapt[k]++; } for(auto it = mapt.begin();it!=mapt.end();it++) { if(it->second==1) dcnt++; if(it->second>=2) cnt2++; } if(dcnt%2==1) dcnt++; // cout<<cnt2<<"~"<<dcnt<<endl; cout<<cnt2+dcnt/2<<endl; mapt.clear(); } }