题意
对于一个数组 ,设元素 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;
}