http://www.usaco.org/index.php?page=viewproblem2&cpid=625
题意:
有一个(0,0)(A,B)的矩阵,然后有n条横线,m条竖线。这些线的交点之间的线段可以被一次性删除。这些线得到了(n+1)(m+1)个空间,问让所有空间联通的删除线总长度最少。
代码:
由克鲁斯卡尔得最小生成树可知,所有线段之间,从小到大删除是没问题的。
可以一组线同时删除:
删除时可能有一些空间本身就联通,例如下图中尝试删除当前列时,134已经联通,所以只需要删除
4
−
(
3
−
1
)
4-(3-1)
4−(3−1)条即可
公式:(cnt2为已经联通的行数量,cnt1为已经联通的列数量)
i
f
(
c
n
t
1
∧
c
n
t
2
)
:
a
n
s
+
=
l
e
n
∗
(
n
−
(
c
n
t
2
−
1
)
)
if(cnt_1\wedge cnt_2):ans+=len*(n-(cnt_2-1))
if(cnt1∧cnt2):ans+=len∗(n−(cnt2−1))
代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
typedef long long LL;
#define pill pair<int,int>
#define se second
#define fi first
const int maxn=5e4+9;
void show(int i){
cout<<"show "<<i<<endl;
}
int cnt;
pill p[maxn];
int a[maxn],b[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int A,B,n,m;
cin>>A>>B>>n>>m;
LL ans=0;
rep(i,1,n)cin>>a[i];
rep(i,1,m)cin>>b[i];
sort(a+1,a+1+n);
sort(b+1,b+1+m);
int pre=0;
rep(i,1,n){
p[++cnt]={a[i]-pre,1};
pre=a[i];
}
p[++cnt]={A-pre,1};
pre=0;
rep(i,1,m){
p[++cnt]={b[i]-pre,2};
pre=b[i];
}
p[++cnt]={B-pre,2};
sort(p+1,p+1+cnt);
// rep(i,1,cnt){
// cout<<p[i].fi<<" "<<p[i].se<<endl;
// }
int cnt_1=0,cnt_2=0;
rep(i,1,cnt){
if(p[i].se==1){
if(cnt_2&&cnt_1){
//cout<<"line1 "<<p[i].fi<<",ans+="<<1ll*p[i].fi*(m+1-cnt_2)<<endl;
ans+=1ll*p[i].fi*(m+1-cnt_2);
}
else{
//cout<<"line2 "<<p[i].fi<<",ans+="<<1ll*p[i].fi*m<<endl;
ans+=1ll*p[i].fi*m;
}
cnt_1++;
}
else{
if(cnt_1&&cnt_2){
//cout<<"col1 "<<p[i].fi<<",ans+="<<p[i].fi*(n+1-cnt_1)<<endl;
ans+=1ll*p[i].fi*(n+1-cnt_1);
}
else{
//cout<<"col2 "<<p[i].fi<<",ans+="<<p[i].fi*n<<endl;
ans+=1ll*p[i].fi*n;
}
cnt_2++;
}
}
cout<<ans<<endl;
}