其他分享
首页 > 其他分享> > Codeforces Round #813 (Div. 2) (C~D)

Codeforces Round #813 (Div. 2) (C~D)

作者:互联网

C. Sort Zero

最开始写了个n2的 TLE了以后 不知道咋优化
只好观察性质 发现我们要维护一个后缀 很多人说要维护前缀 其实也就少跑了60ms 我们维护一个mp[]记录的是哪个数不合法了 然后后面维护后缀时细节有点多 就没啥了

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
const int M = 1<<10;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);

signed main(){
    fast
    int T;cin>>T;
    while(T--){
        int n;cin>>n;
        vector<int>a(n+1);
        map<int,int>mp;
        int mx=0;
        set<int>s;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            s.insert(a[i]);
            if(a[i-1]!=a[i])mp[a[i]]++;
            if(mp[a[i]]>=2){
                mx=max(mx,i);
            }
        }
        int cnt=1;
        for(int i=n;i>=mx+1;i--){
            if(i-1>0){
                if(a[i]>a[i-1]&&mp[a[i-1]]<=1)cnt++;
                else if(a[i]==a[i-1]&&mp[a[i-1]]<=1)continue;
                else break;
            }
        }
        if(mp[a[n]]>=2)cnt=0;
        cout<<s.size()-cnt<<endl;
    }
    return ~~(0^_^0);
}

1712D - Empty Graph

看到最大最小值 我们考虑二分 要是我们check(mid)时 有a[i]<ans/2上取整 那比不可能使其存在 我们让他修改到1e9或者随便一个大于等于ans/2的值都可以
最后我们考虑k剩下多少 要是k剩下2那么一定可以让一对变成1e9其他都是合法的 自然return 1 k要是不剩 我们就要查看每对有没有大于ans的 有就return1
最后k要是剩下1 我们分情况讨论 要是k原本就是2以上的 那我们已经变了一个1e9了 那自然在其旁边变个1e9 就可以了 要是原本只有1 那我们必须check每个的最大值 让后看其最大值>=ans

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
const int M = 1<<10;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int n,k;
vector<int>a;
bool check(int ans){
    int res=0,mx=0;
    auto b=a;
    for(int i=0;i<n;i++){
        if((ans+1)/2>b[i]){
            b[i]=1e9;
            res++;
        }
    }
    int maxv=0;
    for(int i=0;i<n;i++){
        maxv=max(maxv,b[i]);
        if(i<n-1)mx=max(mx,min(b[i],b[i+1]));
    }
    if(k>=res){
        if(k==res){
            return mx>=ans;
        }else if(k==res+1){
            if(k==1){
                return maxv>=ans;
            }else{
                return true;
            }
        }else return true;
    }else return false;
}
signed main(){
    fast
    int T;cin>>T;
    while(T--){
        cin>>n>>k;
        a.clear();
        for(int i=1;i<=n;i++){int x;cin>>x;a.push_back(x);}
        int l=0,r=1e9;
        while(l<r){
            int mid=(l+r+1)/2;
            if(check(mid))l=mid;
            else r=mid-1;
        }
        cout<<l<<endl;
    }
    return ~~(0^_^0);
}

还有就是关于这道贪心的证明 我看很多人都没解释 我这里通俗解释一下啊 代码就不贴了
我们最大值来源有两个 一个是mn*2 来的 一个就是自身本来权重就大来的
我们贪心处理前k-1个 再枚举最后一个1e9放哪 可以抽象看成我们把一个1e9放在另一个1e9(其实是大于ans的就可以)旁边 然后我们就可以get一个mn*2
但是枚举这个确实包括了自身本来权重就大这个是为什么呢 换言之 为啥自身本来权重就大 要从小到大删 其实我写这段话的时候就清楚了 我们乱搞出来就是要删第k短的边
所以很多人写的题解是两部分 一步就是删第k短 另一个就是枚举另一个数该放在哪个大数旁边 让后get一个低保

标签:return,int,res,Codeforces,ans,1e9,Div,813,mx
来源: https://www.cnblogs.com/ycllz/p/16586811.html