题意:给你一个多重集,求
(
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;
}