CF1637E Best Pair

在这里插入图片描述
题意:给你一个多重集,求 ( x + y ) × ( c n t x + c n t y ) (x+y)\times(cnt_x+cnt_y) (x+y)×(cntx+cnty)的最大值,其中 x ! = y x!=y x!=y且有 m m m ( x , y ) (x,y) (x,y)是不能选的
首先枚举 ( x , y ) (x,y) (x,y) O ( N 2 ) O(N^2) O(N2)的,我们考虑枚举 ( c n t x , c n t y ) (cntx,cnty) (cntx,cnty),因为不同的 c n t x cntx cntx O ( N ) O(\sqrt N) O(N )的,先枚举 ( c n t x , c n t y ) (cnt_x,cnt_y) (cntx,cnty)。对于出现次数为 c n t x cnt_x cntx数量的数字可以从大到小贪心选取。
构建一个优先队列,初始 p u s h ( 1 , 1 ) push(1,1) push(1,1),表示 c n t x cnt_x cntx集合中最大的数和 c n t y cnt_y cnty集合中最大的数。(这个过程和那个轮廓线+优先队列的过程非常像),如果 ( 1 , 1 ) (1,1) (1,1)非法就继续放入 ( 1 , 2 ) 和 ( 2 , 1 ) (1,2)和(2,1) (1,2)(2,1)重复该操作直到找到第一个合法的,就是 c n t x cnt_x cntx c n t y cnt_y cnty的最大值。这样就可以 O ( N + M l o g ( M ) ) O(N+Mlog(M)) O(N+Mlog(M))完成。
其实感觉下来还是很简单写意的,写起来可能稍微有一些细节。
D题太简单就不水了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node
{
    int x,y;
    int val;
    bool operator<(const node &ths)const
    {
        return val<ths.val;
    }
};
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        vector<int>a(n+1);
        map<int,int>mp;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            mp[a[i]]++;
        }
        set<pair<int,int>>bad;
        for(int i=1;i<=m;i++)
        {
            int tu,tv;
            scanf("%d%d",&tu,&tv);
            if(tu>tv)swap(tu,tv);
            bad.insert({tu,tv});
        }
        for(int i=1;i<=n;i++)bad.insert({a[i],a[i]});

        int N=sqrt(n);
        vector<pair<int,int>>huge;
        vector<vector<int>>small(N+1);
        for(auto [fi,se]:mp)
        {
            if(se<N)small[se].push_back(fi);
            else huge.push_back({fi,se});
        }
        for(int i=1;i<N;i++)sort(small[i].begin(),small[i].end(),greater<int>());
        ll ans=-1e18;
        for(int size=2;size<=2*N-2;size++)
        {
            for(int sizex=1;sizex<min(size,N);sizex++)
            {
                int sizey=size-sizex;

                if(sizey<N&&sizex<=sizey)
                {
                    int mark1=0,mark2=0;
                    set<pair<int,int>>vis;
                    priority_queue<node>q;
                    if(mark1<small[sizex].size()&&mark2<small[sizey].size())
                    q.push({mark1,mark2,small[sizex][mark1]+small[sizey][mark2]});

                    vis.insert({mark1,mark2});
                    while(!q.empty())
                    {
                         auto [x,y,val]=q.top();
                         int tx=small[sizex][x],ty=small[sizey][y];
                         if(tx>ty)swap(tx,ty);
                         if(bad.count({tx,ty}))
                         {
                            if(x+1<small[sizex].size()&&vis.count({x+1,y})==0)
                            {
                                q.push({x+1,y,small[sizex][x+1]+small[sizey][y]});
                                vis.insert({x+1,y});
                            }
                            if(y+1<small[sizey].size()&&vis.count({x,y+1})==0)
                            {
                                q.push({x,y+1,small[sizex][x]+small[sizey][y+1]});
                                vis.insert({x,y+1});
                            }
                         }
                         else
                         {
                            ans=max(ans,1LL*size*val);
                            break;
                         }

                         q.pop();

                    }

                }
            }
        }
        for(int i=0;i<huge.size();i++)
        {
            for(int j=i+1;j<huge.size();j++)
            {
                auto [num1,cnt1]=huge[i];
                auto [num2,cnt2]=huge[j];
                if(bad.count({num1,num2})==0)ans=max(ans,1LL*(1LL*num1+num2)*(1LL*cnt1+cnt2));
            }
        }
        for(int i=0;i<huge.size();i++)
        {
            auto [NUM,cnt]=huge[i];
            for(int j=1;j<N;j++)
            {
                for(auto num:small[j])
                {

                    if(bad.count({min(num,NUM),max(num,NUM)})==0)
                    {
                        ans=max(ans,1LL*(1LL*NUM+num)*(1LL*cnt+j));
                        break;
                    }
                }
            }
        }
        printf("%lld\n",ans);


    }
    return  0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值