其他分享
首页 > 其他分享> > Codeforces Round #793 (Div. 2)

Codeforces Round #793 (Div. 2)

作者:互联网

Codeforces Round #793 (Div. 2)

C

题意

给定一个长度为 \(n\) 的序列 \(a\) ,它的反串是 \(a'\) 。

现在重排这个 \(a\)

最大化 \(min(LIS(a),LIS(a'))\)

思路

一开始一直在想怎么构造出来,最后发现还是从 “对答案的贡献” 的角度分析···

维护两个集合,分别为构成正串 \(a\) 的 \(LIS\) 的集合 \(s1\) ,和构成正串 \(a\) 的 \(LCS\) 的集合 \(s2\) 。

我们要最大化 \(min(LIS(a),LIS(a'))\) 。就不能让任意一方格外小,所以我们依次维护 \(s1,s2\) 。

可以发现对于序列中一个数字 \(x\) ,如果这个数字出现的次数大于 \(2\) ,就不会再对答案有贡献。比如,\([1,2,2,2,3,4]\) 有, \(s1 = {1,2,3}\) ,\(s2 ={2,4}\) 。第三个 \(2\) 已经不会再对答案有贡献。

进而的,我们可以将数字分为 仅出现一次出现大于一次 的两类。第二类如上,会对答案造成 "加一的贡献"。第一类由于只能放入其中一个集合中,每两个第一类数字加入 \(s1\) ,\(s2\) 才会对答案有 “加一的贡献”。这可以等价于对答案有 "0.5的贡献"。

特别的,对于第一类数字,可以存在一个数字 \(y\) 复用 使得这个 \(y\) 的贡献变为 \(1\)。比如 序列 \([1 ,1, 4, 5, 2, 4, 5, 5, 4, 4]\) 最后的最优构造序列是 \([1 ,4, 4, 5, 4, 2, 1, 4, 5, 5]\) 。其中 \(s1 = 1,2,4,5\) 。 \(s2 = 1,2,4,5\) 。这里面的 \(2\) 得到了复用。

也就是第一类 “0.5的贡献”变为了 \(1\) 。

因此最后答案应该是 第一类数贡献的上取整加上第二类数的贡献

代码非常简单。

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N; cin >> N;
    map<int,int> mp;
    for(int i = 0;i < N;i ++) {
        int t; cin >> t;
        mp[t] ++;
    }
    int x = 0, y = 0;
    for(auto [v,c] : mp) {
        if(c == 1) x ++;
        else y ++;
    }
    cout << y + (x + 1) / 2 << endl;
    /* 
        4
        1 4 4 5 4 2 1 4 5 5

        5 4 2 1
        1 2 4 5
     */
    
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

标签:793,int,s2,Codeforces,long,贡献,LIS,Div,define
来源: https://www.cnblogs.com/Mxrush/p/16300928.html