2018百度之星初赛B轮部分题题解

由于昨天那场和牛客多校冲突了,就没打A轮。听说昨天题还很难。。。

而今天题目难度着实跨度太大,前三题都属于签到题,稍微想一想都能做出来。

但后面的题,怕是神仙题了。。。

弱弱的我用了1个半小时才A完3题,自然是滚粗复赛了。。。

下面看一下这几道题

-----------------------------------------------------------------------------------------------------------------------------------------------

1001 degree (hdu6380)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6380

刚开始看这道题,思路其实并不是特别明显。看了一会发现,首先,找出原图中度最大的点,对每个点dfs一次。每个点访问一次,复杂度O(n)。每次dfs时,sum++(也就是未与度最大的点联通的联通块数)(看看代码就懂了)。

当有k次操作时,每次相当于对度最大点所在的联通块减下来一个点,也就是度加1。

注意:答案最大为n-1,最后不要让答案超过n-1

代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm> 
using namespace std;
const int MAXV = 2e5+10;
int d[MAXV];
vector<int> g[MAXV];
bool vis[MAXV];
int cnt=0;
int sum=0;
void dfs(int x)
{
	vis[x]=true;
	cnt++;
	int len=g[x].size();
	for(int i=0;i<len;i++)
	{
		 if(!vis[g[x][i]])
		 dfs(g[x][i]);
	}
}
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	int t;
	int n,v,u,m,k;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&k);
		for(int i=0;i<n;i++)
		g[i].clear();
		cnt=0;
		sum=0;
		for(int i=0;i<n;i++)
		vis[i]=false;
		for(int i=0;i<n;i++)
		d[i]=0;
		for(int i=1;i<=m;i++)
		{
		   scanf("%d%d",&u,&v);
		   g[u].push_back(v);
		   g[v].push_back(u);
		   d[u]++;
		   d[v]++;
	    }
	    int maxd=-1,maxid=-1;
	    for(int i=0;i<n;i++)
	    {
	    	if(d[i]>maxd)
	    	{
	    		maxd=d[i];
	    		maxid=i;
			}
		}
		vis[maxid]=true;
		for(int i=0;i<n;i++)
		{
			if(i!=maxid&&vis[i]==false)
			{
				dfs(i);
				sum++;
			}
		}
        sum+=k;
        sum=min(n-1,sum);
	    printf("%d\n",sum);
	}
	return 0;
}

1004  p1m2(hdu6383)

 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6383

这道题还是很套路的。看到题面中最小值最大化 -> 果断二分。

二分每一个可能的答案,检查这个答案是否满足要求。

具体检查方法就是,看当前需要补得数和超过的数之间的关系,看代码就能懂。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm> 
using namespace std;
typedef long long ll;
int n;
ll a[300010];
ll maxnum;
bool check(ll x)
{
	ll bu,guo;
	bu=0,guo=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]<x)
		{
			bu+=x-a[i];
		}
		else if(a[i]>x)
		{
			guo+=(a[i]-x)/2;
		}
	}
	if(guo<bu)
	return false;
	if(guo>=bu)
	return true;
}
ll ans;
void b_search()
{
	ll lb=0;
	ll rb=maxnum;
	while(lb<=rb)
	{
		ll mid=(lb+rb)/2;
		if(check(mid))
		{
			ans=max(ans,mid);
			lb=mid+1;
		}
		else
		{
			rb=mid-1;
		}
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		maxnum=0;
		for(int i=1;i<=n;i++)
		{
		   scanf("%I64d",&a[i]);
		   maxnum=max(maxnum,a[i]);
	    }
		ans=0;
		b_search();
		printf("%I64d\n",ans);
	}
	return 0;
}

1006   rect(hdu6385) 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6385

其实这道题才是全场最水的题,关键点在于题目中有个重要条件,任意两点不在同一行同一列。 

所以说,直接看每一个点离4条边哪个进选哪个就好了(不会相交,没有必要证,可以自己画画)。

代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm> 
using namespace std;
typedef long long ll;
int main()
{
	int t;
	ll n,mx,my;
	ll d1,d2,d3,d4;
	ll x,y;
	scanf("%d",&t);
	ll sum;
	while(t--)
	{
		sum=0;
		scanf("%I64d%I64d%I64d",&mx,&my,&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%I64d%I64d",&x,&y);
			d1=x;
			d2=mx-x;
			d3=y;
			d4=my-y;
			sum+=min(min(d1,d2),min(d3,d4));
		}
		printf("%I64d\n",sum);
	}
	return 0;
}

--------------------------------------------------------------------------------------------------------------------------------------------------

最后的一个多小时一直刚1002了,不过这道题过的人极少。。。

我写了个暴力,幻想着万一数据不强(不可能的),最后理所当然的T了。

今天其实打的还行吧,就是手(nao)慢(can)了点,明年再战。。。 

猜你喜欢

转载自blog.csdn.net/star_moon0309/article/details/81612000