Codeforces Round #495 (Div. 2) (ABCE) 题解

题目链接:http://codeforces.com/contest/1004

A题题意:Sonya想在N个城市之间开店,他的每个店到城市的距离为d,求最多能开多少家店。

A题题解:遍历相邻两城市距离,大于2*d就可以开两家,等于开一家,小于不能开即可。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
const int maxn = 1e2+7;
int n,m,k,a[maxn];
map<int,int> Q;
int main(int argc, char const *argv[])
{
	cin>>n>>m;
	int ans = 2;
	_for(i,1,n)cin>>a[i];
	_for(i,2,n)
	{
		k=a[i]-a[i-1];
		if(k>2*m)ans+=2;
		else if(k==2*m)ans++;
	}
	cout<<ans<<endl;
	return 0;
}

B题题意:构造一个只含01的数组,给定K个区间,每个区间贡献为区间内0个数*1的个数,构造一个贡献和最大的情况。

B题题解:根据基本不等式很容易知道两数和一定,相等的时候乘积最大,所以直接010101010即可。

AC代码:

/*
* @Author: 王文宇
* @Date:   2018-07-06 00:50:16
* @Last Modified by:   王文宇
* @Last Modified time: 2018-07-06 00:53:01
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
const int maxn = 1e3+7;
int n,m,ans;
int main(int argc, char const *argv[])
{
	cin>>n>>m;
	_for(i,1,m)
	{
		int x,y;
		cin>>x>>y;
	}
	_for(i,1,n)
	{
		if(i&1)cout<<0;
		else cout<<1;
	}
	cout<<endl;
	return 0;
}

C题题意:给定一个整数数组,一个机器人初始位置在最左边,一个在最右边,每个机器人有一个数值,机器人碰见相同的数字就好停下,可以给两个机器人任意数值使得他们不会相撞,求有多少组数。

C题题解:用一个集合统计有多少个不同的数,然后从第一个数往后遍历即可,每次记录当前这个数已经使用过,在后面在碰见则直接跳过即可。因为这个组合一定在前面存在过。

AC代码:

/*
* @Author: 王文宇
* @Date:   2018-07-06 01:01:24
* @Last Modified by:   王文宇
* @Last Modified time: 2018-07-06 01:08:37
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
const int maxn = 1e5+7;
int n,m,a[maxn],vis[maxn],gg[maxn];
ll ans;
set<int> S;
int main(int argc, char const *argv[])
{
	cin>>n;
	_for(i,1,n)
	{
		cin>>a[i];
		vis[a[i]]++;
		S.insert(a[i]);
	}
	int k = S.size();
	_for(i,1,n-1)
	{	
		vis[a[i]]--;
		if(vis[a[i]]==0)k--;
		if(gg[a[i]]!=1)ans+=k;
		gg[a[i]]=1;
	}
	cout<<ans<<endl;
	return 0;
}

E题题意:给N个点,N-1条边的距离,然后给定一个整数K,可以选择任意连续的K个点进行标记,最小化没标记的点到标记点的最短距离的最大值,求该最大值。

E题题解:该题把K的限制改为长度的限制即为BZOJ1999,首先可以想到标记的点一定是直径上的点,先两次bfs跑出直径,然后遍历直径上的各点再跑一次dfs即一个外生成树,去记录该点到未标记的最远距离,那么对于该标记点的最小值一定是直径端点到该点的距离与外生成树的最远距离中的最大值。接下来就是单调队列去维护滑动区间去找答案即可。对于最小化最大值的题也可以直接去二分答案。

AC代码:

/*
* @Author: 王文宇
* @Date:   2018-07-06 01:38:57
* @Last Modified by:   王文宇
* @Last Modified time: 2018-07-07 01:36:06
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
const int maxn = 1e5+7;
const int inf = 0x3f3f3f3f;
vector<pair<int,int> > E[maxn];
vector<int> S;
vector<int> leng;
vector<int> tree;
int n,k,vis[maxn],pre[maxn],d[maxn],d2[maxn];
void dfs(int x)
{
	vis[x]=1;
	int l = E[x].size()-1;
	_for(i,0,l)
	{
		int next = E[x][i].first;
		if(!vis[next])
		{
			d[next]=d[x]+E[x][i].second;
			dfs(next);
		}
	}
}
void dfs1(int x)
{
	vis[x]=1;
	int l = E[x].size()-1;
	_for(i,0,l)
	{
		int next = E[x][i].first;
		if(!vis[next])
		{
			pre[next]=x;
			d[next]=d[x]+E[x][i].second;
			dfs1(next);
		}
	}	
}
int dis(int x)
{
	vis[x]=1;
	int l = E[x].size()-1;
	_for(i,0,l)
	{
		int next = E[x][i].first;
		if(!vis[next])
		{
			
			d2[x]=max(d2[x],dis(next)+E[x][i].second);
		}
	}
	return d2[x];	
}
int main(int argc, char const *argv[])
{
	cin>>n>>k;
	_for(i,1,n-1)
	{
		int x,y,z;
		cin>>x>>y>>z;
		E[x].push_back(make_pair(y,z));
		E[y].push_back(make_pair(x,z));
	}
	dfs(1);
	int now=0,t=1;
	_for(i,1,n)
	{
		if(d[i]>now)
		{
			now=d[i];
			t=i;
		}
		d[i]=0;
		vis[i]=0;
	}
	dfs1(t);
	now=0;
	_for(i,1,n)
	{
		if(d[i]>now)
		{
			now=d[i];
			t=i;
		}
		vis[i]=0;
	}
	for(int i=t;i!=0;i=pre[i])
	{
		vis[i]=1;
		S.push_back(i);
	}
	int ddd = (int)S.size();
	_for(i,0,ddd-1)
	{
		dis(S[i]);
		leng.push_back(d[S[i]]);
		tree.push_back(d2[S[i]]);
	}
	reverse(S.begin(),S.end());
	reverse(leng.begin(),leng.end());
	reverse(tree.begin(),tree.end());
		//_for(i,0,S.size()-1)cout<<S[i]<<" "<<leng[i]<<" "<<tree[i]<<endl;
	
	k=min(k,ddd);
	int ans = inf;
	deque<pair<int,int> > Q;

	for(int i=0,j=0;i+k<=ddd;i++)
	{
		while(j<i+k)
		{
			while(!Q.empty()&&Q.back().first<tree[j])Q.pop_back();
			Q.push_back(make_pair(tree[j],j));
			j++;
		}
		while(Q.front().second<i)Q.pop_front();
		ans = min(ans,max(max(leng[i],leng.back()-leng[i+k-1]),Q.front().first));
	}
	cout<<ans<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值