CF1637E. Best Pair

Link

题意

对于一个数组 ,设元素 x x x 在其中出现了 c n t x cnt_x cntx 次。 S S S 是一些禁止选择的二元组形如 ( x , y ) (x, y) (x,y),表示不能取 ( x , y ) ( y , x ) (x,y)(y,x) (x,y)(y,x),求 ( c n t x + c n t y ) ( x + y ) 的 最 大 值   ( x ≠ y ) (cnt_x+cnt_y)(x+y) 的最大值\space (x \neq y) (cntx+cnty)(x+y) (x=y)

思路

本质不同的 c n t cnt cnt数量在 O ( n ) O(\sqrt n) O(n )数量级,所以建立map<int, vector<int> > mp;,其中 m p [ i ] mp[i] mp[i]表示出现了 i i i 次的数组成的数组。
然后枚举两个 c n t cnt cnt值,各从中选一个且未被禁选,使它们的加和最大。这样每两个cnt得出一个最大值,最后取并即可。
类似于已知 a , b a,b a,b 两个数组,求 a i + b j a_i+b_j ai+bj n 2 n^2 n2 个数的第 k k k 大。
用优先队列+ bfs 即可。

代码

int n, m;
map<pair<int,int>, int> bad;
map<int, int> cnt;
map<int, vector<int> > mp;
int bfs(vector<int> a, vector<int> b) {
    map<pair<int, int>, bool> vis;
    priority_queue<array<int, 3> > q;
    q.push(array<int,3>{a.back() + b.back(),(int)a.size()-1, (int)b.size() - 1});
    while(!q.empty()) {
        auto i = q.top();
        int val = i[0], x = i[1], y = i[2];
        q.pop();
        if(a[x] != b[y] && !bad[make_pair(a[x], b[y])]) return val;
        if(x && !vis[make_pair(a[x-1], b[y])]) {
            q.push(array<int,3>{a[x-1]+b[y], x-1, y});
            vis[make_pair(a[x-1], b[y])] = 1;
        }
        if(y && !vis[make_pair(a[x], b[y-1])]) {
            q.push(array<int, 3>{a[x]+b[y-1], x, y-1});
            vis[make_pair(a[x], b[y-1])] = 1;
        }
    }
    return 0;
    
}
void solve() {
    cin >> n >> m;
    bad.clear();
    cnt.clear();
    mp.clear();
    for(int i = 1; i <= n; i++) {
        int x;
        cin >> x; cnt[x]++;
    }
    for(int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        bad[make_pair(x, y)] = 1;
        bad[make_pair(y, x)] = 1;
    }
    for(auto i : cnt)
        mp[i.second].pb(i.first);
    for(auto it : mp)
        sort(it.second.begin(), it.second.end());
    int ans = 0;
    for(auto i: mp) {
        for(auto j: mp) {
            if(j.fi < i.fi) continue;
            int tmp = bfs(i.se, j.se);
            ans = max(ans, (i.fi + j.fi) * tmp);
        }
    }
    cout << ans << endl;   
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值