P3505 [POI2010]TEL-Teleportation 题解
解题思路:
将整个图分成有顺序的
将第一个点放在第一个部分,与第一个点直接相连的部分放在第二个部分,与第二个部分有连边的放在第三个部分。再将第二个点放在第六个部分,与第二个点直接相连的放在第五个部分,与第五个部分有连边的放在第四个部分。都不满足的先放一边。
然后对于每一个部分的内部,一定可以任意连边,这一部分的价值可以直接统计。相邻的两个部分之间也可以直接连边,代价也可以直接算出来。
最后将那些都不满足的边放到中间两个部分中能产生最大价值的就行了。
注意题目要求的是增加的边的数量,需要减去原有的边数
最后一步分配剩余的点的正确性证明:
先考虑只有一个点的情况。不妨设第二部分到第五部分的点的数量分别为
然后分情况讨论,将这个点放在第一到第五个部分能产生的价值分别是:
由此拓展到多个点,由之前一个点的推导,这样的一些点一定是放在中间两个部分中的一个,所以不妨设总共有
此时可以将产生的总价值表示为
这是一个
代码:
#include<cstdio>
using namespace std;
#define int long long
const int MAXN=4000005;
int n,m,head[MAXN],nxt[MAXN],num[MAXN],x,y,cnt,col[MAXN],cnt2,cnt5,cnt3,cnt4,ans;
void add(int x,int y){
nxt[++cnt]=head[x];head[x]=cnt;num[cnt]=y;
}
signed main(){
scanf("%lld%lld",&n,&m);
col[1]=1;col[2]=6;
for(int i=1;i<=m;i++){
scanf("%lld%lld",&x,&y);
add(x,y);add(y,x);
}
for(int i=head[1];i;i=nxt[i]){
col[num[i]]=2;cnt2++;
}
for(int i=head[2];i;i=nxt[i]){
col[num[i]]=5;cnt5++;
}
for(int i=1;i<=n;i++){
if(col[i]==2){
for(int j=head[i];j;j=nxt[j])
if(col[num[j]]==0)col[num[j]]=3,cnt3++;
}
if(col[i]==5){
for(int j=head[i];j;j=nxt[j])
if(col[num[j]]==0)col[num[j]]=4,cnt4++;
}
}
for(int i=1;i<=n;i++)
if(col[i]==0){
if(cnt2>cnt5)cnt3++;
else cnt4++;
}
ans=cnt2+cnt5+cnt2*(cnt2-1)/2+cnt3*(cnt3-1)/2+cnt4*(cnt4-1)/2+cnt5*(cnt5-1)/2
+cnt2*cnt3+cnt3*cnt4+cnt4*cnt5-m;
printf("%lld\n",ans);
return 0;
}