题解:P10768 「CROI · R2」落月摇情
昨夜闲潭梦落花,可怜春半不还家。
江水流春去欲尽,江潭落月复西斜。
Solution P10768
::::info[Problem 1]{open}
这
::::success[Solution to Problem 1]
首先,
证明是显然的:你要保证所有点都联通,所以你选择一个 MST。现在联通了,那你贪心的选择最小的加进去就行。 ::::
::::info[Problem 2] 如何求 MST? ::::
::::success[Solution to Problem 2] 不难发现:
- 如果
a_i<0 ,则你给他连上a_i 的最大值位置最佳; - 如果
a_i>0 ,则你给他连上a_i 的最小值最佳; - 如果
a_i=0 ,你随便连,归到上面一类解决。
解决了 MST 问题。 ::::
::::info[Problem 3] 如何往上面加非 MST 边? ::::
::::success[Solution to Problem 3]
很显然可以把所有边都算一遍排个序,但是复杂度
你可以先对
设
那么你会发现:如果某个点
同理,小于
这样你只会处理
::::error[小问题]
两步中,MST 中的边可能会被第二步也处理到。加上 MST 中的边也可能发生重复(例如
::::success[Solution]
最简单的想法是拿一个 map 存一下这条边是不是被加了,但是常数太大加之带
于是改用 gp_hash_table,这是一个 pb_ds 库里的东西,在 CCF 系列竞赛中可以使用。在日常调试中,需要:
#include<bits/extc++.h>
using namespace __gnu_pbds;
::::
::::success[AC Code]
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define fastio ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define ls (now<<1)
#define rs ((now<<1)|1)
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
const int N=1000005;
const int mod=1;
const int intinf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
struct node{
ll w;
int u,v;
friend bool operator <(node _,node __){
return _.w>__.w;
}
};
node make_node(int u,int v,ll w){
node rrat;
rrat.u=u;
rrat.v=v;
rrat.w=w;
return rrat;
}
gp_hash_table<int,int>mp[N];
std::priority_queue<node>q;
struct Node{
int a,id;
friend bool operator <(Node _,Node __){
return _.a<__.a;
}
}A[N];
ll a[N];int id[N];
int n,m;
ll sum=0;
vector<pair<int,int> >ans;
void add(int u,int v){
if(mp[u][v]||u==v)return;
ans.push_back(make_pair(u,v));
mp[u][v]=1;mp[v][u]=1;
sum+=a[u]*a[v];
}
signed main(){
fastio;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>A[i].a;A[i].id=i;
}
sort(A+1,A+n+1);
for(int i=1;i<=n;i++){
a[i]=A[i].a;
id[i]=A[i].id;
}
for(int i=1;i<=n;i++){
if(a[i]<0){
add(i,n);
q.push(make_node(i,n,a[i]*a[n]));
}
else {
add(i,1);
q.push(make_node(i,1,a[i]*a[1]));
}
}
int cnt=n-1;
while(!q.empty()&&cnt<m){
node tmp=q.top();q.pop();
int u=tmp.u,v=tmp.v;
if(a[u]>=0){
if(v!=n)q.push(make_node(u,v+1,a[u]*a[v+1]));
}
else{
if(v!=1){
q.push(make_node(u,v-1,a[u]*a[v-1]));
}
}
if(mp[u][v])continue;
if(u==v)continue;
cnt++;
add(u,v);
}
cout<<sum<<'\n';
for(auto p:ans){
cout<<id[p.fi]<<' '<<id[p.se]<<'\n';
}
return 0;
}
::::