吐槽CSDN,这篇博客我编辑了半天,发表之后竟然没变,感觉像是日了狗了,强迫症的我当然要再写一遍。
比赛链接:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=826
1001:HDU6380
1004:HDU6383
1006:HDU6385
bestcoder首页的官方题解简直是业界良心,建议作为参考:http://bestcoder.hdu.edu.cn/
1001 | degree |
题意:给定一个有 N 个点以及 M 条边的无向简单图,此图中保证没有任何圈 (cycle) 存在,也就是有多棵树的深林。
现在你可以对此图依序进行以下的操作:
问最后此图中度数 (degree) 最大的点的度数可以多大呢?
解析:首先考虑有多个联通分量,此时找到度数最大的节点V0,发现可从V0每对一个联通分量连一条新边(连到任意点)就能使度数加一且不产生圈。
将多个两桶分量连成一个后,发现没有和V0直接相连的那些边每删除一条就形成一个新的联通分量,就能再连一次使V0度数加1。
代码:
//2018 “百度之星”程序设计大赛 - 初赛(B)- 1001
#include
using namespace std;
typedef long long ll;
const ll MAXN=2*1e5+5;
int N,M,K,num[MAXN];//num[i]存放点i的度数
int a[MAXN],b[MAXN];
//并查集
int father[MAXN];
int Find(int i)
{
int t=father[i];
while(i!=father[i])
{
i=father[i];
}
father[t]=i;
return i;
}
void Union(int i,int j)
{
int f1=Find(i),f2=Find(j);
if(f1!=f2)
father[f1]=f2;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&N,&M,&K);
for(int i=0;i<=N;i++)
{
num[i]=0;
father[i]=i;
}
int maxp=0;//记录度数最大的点
for(int i=1;i<=M;i++)
{
scanf("%d%d",&a[i],&b[i]);
Union(a[i],b[i]);
num[a[i]]++;
num[b[i]]++;
if(num[a[i]]>num[maxp]) maxp=a[i];
if(num[b[i]]>num[maxp]) maxp=b[i];
}
int ans=num[maxp];
set s;
for(int i=0;i=ne)
ans+=ne;
else
ans+=K;
printf("%d\n",ans);
}
return 0;
}
1004 | p1m2 |
题意:一个整数数组为稳定的,当且仅当同时符合以下两个条件:
对数组有一种操作,任取两个元素,对其中一个-2,对另一个+1。现在给定一个整数数组a[],在任意进行操作后,请问在所有可能达到的稳定数组中,拥有最大的『数组中的最小值』的那些数组,此值是多少。
解析:看到“最大的最小”,就想到二分来做。我们二分枚举答案为x,对于大于x的a[i]必须每次-2减到值为x或x+1,那么它必须减(a[i]-x)/2次;对于小于x的a[i]必须每次+1加到值为x,那么它必须加(x-a[i])次,而且它可以再+1加到x+1(也可以不加)。
二分时:
代码来自https://blog.csdn.net/qq_37868325:
#include
using namespace std;
const int inf = 1000000000;
long long a[500500],b,n,T;
long long sum[500500];
int dfs(long long rt)
{
long long p=n+1,x,y=0;
for(int i=1; i<=n; i++)
{
if(a[i]>rt)
{
p=i;
break;
}
}
x=rt*(p-1)-sum[p-1];
for(int i=n; i>=p; i--)
{
y+=(a[i]-rt)/2;
}
//x是必须加的次数,y是必须减的次数,x+p-1是可以加的次数
if(x<=y&&y<=x+p-1) return 1;
if(y
1006 | rect |
题意:有一个大小为 MX×MY 的矩形,左下角坐标为 (0, 0),右上角坐标为 (MX, MY)。此矩形内有 N 个整数坐标的点 (x_i, y_i),x_i 彼此不重复,y_i 彼此也不重复。
现在要从每一个点画出一条线段,满足下列条件:
现在要让画出的线段的长度总和最小,请输出这个最小的长度总和值。
解析:每个点的长度最小值就是到4个边界距离的最小值,由于坐标不重合,枚举任意两个点可以发现,一个点最短距离的选择不会影响另一个的选择,所以求个和就ok。
代码:
//2018 “百度之星”程序设计大赛 - 初赛(B)- 1006
#include
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
int mx,my,n;
int x,y;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&mx,&my,&n);
ll ans=0;
while(n--)
{
scanf("%d%d",&x,&y);
int tmp=min(x,y);
tmp=min(tmp,mx-x);
tmp=min(tmp,my-y);
ans+=(ll)tmp;
}
printf("%I64d\n",ans);
}
return 0;
}