其他分享
首页 > 其他分享> > Codeforces 1637 E. Best Pair —— 思维

Codeforces 1637 E. Best Pair —— 思维

作者:互联网

This way

题意:

给你n个数,cnt[i]表示i出现的次数。
求出最大的(x+y)*(cnt[x]+cnt[y])
x不等于y并且给你一些不能取的对数。

题解:

一开始想的是那种随着值增大出现次数单调递减的二分。但是这种不能取的情况一旦出现就导致可能不是最优的,那么二分怎么做我一下子就想不出来了。
值想不出来换个思路,通过出现次数枚举,我们会发现不同种类的出现次数最多只有 O ( n ) O(\sqrt{n}) O(n ​)次。
最坏情况应该是这样:出现1次的有1个,2次的有1个,3次的有1个…那情况数为(1+x)*x/2<=n。
然后我们由于要使乘积最大,对于相同出现次数的我们只需要找最大的就好了。但是这里有一个问题就是说有不能取的对,所以对于相同出现次数的,我们还是要值从高往低找到能取的值。由于这个时间复杂度是独立的,所以总时间复杂度就是O(NlogN)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5+5;
const ll M=1e9+7;
struct node{
    ll val,num;
}a[N];
#define pll pair<ll,ll>
struct pair_hash{
    template<class T1,class T2>
    std::size_t operator()(const std::pair<T1,T2>&p)const {
        auto h1 = std::hash<T1>{}(p.first);
        auto h2 = std::hash<T2>{}(p.second);
        return h1*M+h2;
    }
};
unordered_map<pll,ll,pair_hash>mp;
unordered_map<ll,ll>num;
ll check(ll x,ll i){
    return (a[x].val+i)*(a[x].num+num[i]);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        num.clear();
        mp.clear();
        int n,k;
        ll x,y;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%lld",&x),num[x]++;
        for(int i=1;i<=k;i++)
            scanf("%lld%lld",&x,&y),mp[{x,y}]=mp[{y,x}]=1;
        ll all=0,mx=0;
        for(auto i :num){
            int l=1,r=all,ans=0,mid;
            if(all){
                while(r>=l){
                    mid=l+r>>1;
                    if(!ans)ans=mid;
                    if(check(mid,i.first)>check(ans,i.first))
                        ans=mid;
                    if(check(mid,i.first)>=check(mid+1,i.first))r=mid-1;
                    else l=mid+1;
                }
                if(mp[{i.first,a[ans].val}]){
                    l=r=ans;
                    while(l&&mp[{i.first,a[l].val}])l--;
                    while(r<=all&&mp[{i.first,a[r].val}])r++;
                    if(l)mx=max(mx,check(l,i.first));
                    if(r-all-1)mx=max(mx,check(r,i.first));
                }
                else
                    mx=max(mx,check(ans,i.first));
            }

            while(all&&i.second>=a[all].num)all--;
            a[++all]={i.first,i.second};
        }
        printf("%lld\n",mx);
    }
    return 0;
}

标签:check,ll,mid,Codeforces,ans,Pair,mx,Best,first
来源: https://blog.csdn.net/tianyizhicheng/article/details/123097753