Educational Codeforces Round 180 (Rated for Div. 2) A-D题解

A. Race

题意

在一个数轴上,奖品可能出现在 x x x 点或 y y y 点,Alice 现在在 a a a 点,请问Bob是否存在一个点 b b b,使得无论奖品出现在 x x x 点还是 y y y 点,Bob都能比Alice先拿到( ∣ b − x ∣ < ∣ a − x ∣ |b-x|<|a-x| bx<ax ∣ b − y ∣ < ∣ a − y ∣ |b-y|<|a-y| by<ay)。注意, b b b 点不可以与 a a a 点重合,但可以与 x x x 点、 y y y 点重合。若存在,输出 YES,否则输出 NO

题目保证 a , x , y a,x,y a,x,y 两两不同。

思路

首先假设 x < y xx<y(若 x > y x>y x>y 就交换一下)。

  • 如果 a < x aa<x ,Bob 一定可以选择 a a a 右边的那个点作为点 b b b,显然满足 ∣ b − x ∣ < ∣ a − x ∣ |b-x|<|a-x| bx<ax ∣ b − y ∣ < ∣ a − y ∣ |b-y|<|a-y| by<ay

  • 如果 a > y a>y a>y,Bob 一定可以选择 a a a 左边的那个点作为点 b b b,显然也满足 ∣ b − x ∣ < ∣ a − x ∣ |b-x|<|a-x| bx<ax ∣ b − y ∣ < ∣ a − y ∣ |b-y|<|a-y| by<ay

  • 否则,即 x < a < y xx<a<y,Bob 选择任何一个点都一定存在 ∣ b − x ∣ > ∣ a − x ∣ |b-x|>|a-x| bx>ax ∣ b − y ∣ > ∣ a − y ∣ |b-y|>|a-y| by>ay 中的一个,所以这种情况一定不可以。

C++ 代码

#include
using namespace std;
void solve(){
	int a,x,y;
	cin>>a>>x>>y;
	if(x>y) swap(x,y);
	if(a<x||a>y){
		cout<<"YES\n";
	}else{
		cout<<"NO\n";
	}
}
int main(){
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

B. Shrinking Array

题意

如果一个数组 b b b 存在至少两个元素,且存在至少一个 i ( 1 ≤ i < n ) i(1\le ii(1i<n),使得 ∣ b i − b i + 1 ∣ ≤ 1 |b_i-b_{i+1}|\le1 bibi+11,则称这个数组是 美丽的

你有一个数组 a a a,你可以按顺序执行以下操作,求出使得数组 a a a美丽的 的最小操作次数,若不能变成,输出 -1

  • 选择一个 i ( 1 ≤ i < n ) i(1\le ii(1i<n),并选择满足 min ⁡ ( a i , a i + 1 ) ≤ x ≤ max ⁡ ( a i , a i + 1 ) \min(a_i,a_{i+1})\le x\le \max(a_i,a_{i+1}) min(ai,ai+1)xmax(ai,ai+1) 的任意一个整数 x x x,随后把 a i , a i + 1 a_i,a_{i+1} ai,ai+1 替换成一个 x x x,很明显这个时候数组长度减小了 1 1 1

思路

观察发现,若数组严格递增或严格递减,且不存在 ∣ a i − a i + 1 ∣ = 1 |a_i-a_{i+1}|= 1 aiai+1=1,则不可以变成 美丽的,答案为 -1。(情况 01 01 01

其它情况下,若已经存在 ∣ a i − a i + 1 ∣ ≤ 1 |a_i-a_{i+1}|\le 1 aiai+11,答案为 0 0 0。(情况 02 02 02

其余情况答案一定是 1 1 1(情况 03 03 03):

  • 证明:这些情况中,数组一定不是严格递增的,肯定存在相邻的三个数 ( a , b , c ) (a,b,c) (a,b,c) , 一定满足一个: b < a < c bb<a<c c < a < b cc<a<b a < c < b aa<c<b b < c < a bb<c<a。一步操作就可以满足了。

C++ 代码

#include
using namespace std;
int v[maxn];
void solve(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>v[i];
    
    //情况01 递增
	bool flag=true;
	for(int i=2;i<=n;i++){
		if(v[i]<=v[i-1]||v[i]-v[i-1]==1){
			flag=false;
			break;
		}
	}
	if(flag){
		cout<<-1<<endl;
		return;
	}
    
    //情况01 递减
	flag=true;
	for(int i=n-1;i>=1;i--){
		if(v[i]<=v[i+1]||v[i]-v[i+1]==1){
			flag=false;
			break;
		}
	}
	if(flag){
		cout<<-1<<endl;
		return;
	}
    
    //情况02
	for(int i=2;i<=n;i++){
		if(v[i-1]==v[i]||abs(v[i]-v[i-1])==1){
			cout<<0<<endl;
			return;
		}
	}
    
    //情况03
	cout<<1<<endl;
}
int main(){
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

C. Coloring Game

题意

一个大小为 n n n 的整数数组 a a a

最初,数组中的所有元素都是无色的。首先,Alice 选择 3 3 3 个元素并将它们染成红色。然后 Bob 可以选择任意 1 1 1 个元素染成蓝色(如果该元素原本是红色,则会被重新着色)。如果所有红色元素的总和严格大于蓝色元素的值,爱丽丝就获胜。

你的任务是计算爱丽丝有多少种选择 3 3 3 个元素的方法,可以确保无论鲍勃如何操作都能获胜。

题目保证 a a a 数组单调不减。

思路

很明显,我们可以暴力枚举前两个元素,然后查找第三个元素,假设 a , b , c ( a ≤ b ≤ c ) a,b,c(a\le b\le c) a,b,c(abc) 为这三个元素,则必须满足 a + b > c a+b>c a+b>c a + b + c > max ⁡ a i a+b+c>\max{a_i} a+b+c>maxai

可以想到用双指针,具体内容请看代码。

C++ 代码

#include
#define int long long
using namespace std;
const int maxn=5005;
int v[maxn];
void solve(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>v[i];
	}
	int ans=0;
	for(int i=2;i<=n-1;i++){
		int l=0,r=i-1;
		while(l<r){
			if(v[l]+v[r]>max(v[n-1]-v[i],v[i])){
				ans+=r-l;
				r--;
			}else{
				l++;
			}
		}
	}
	cout<<ans<<endl;
}
signed main(){
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

D. Reachability and Tree

题意

一棵树有 n n n 个节点,你要给出一种方案,给每条边加上方向,要存在恰好 n n n 个数对 ( u , v ) (u,v) (u,v),使得 u u u v v v 之间有路径;或者说明这是不可能的。

思路

首先,不管怎么加方向,一定存在至少 n − 1 n-1 n1 个这样的数对,就是每条边的两个点都可以组成一个数对,所以,只要再加上一对即可。

如果只要 n − 1 n-1 n1 对,若 1 1 1 为根节点,我们可以想到这样子加边:第一层全朝上,第二层全朝下,以此类推。

Educational Codeforces Round 180 (Rated for Div. 2) A-D题解_第1张图片

要想再加上一条边,应该找一个 2 2 2 度点,它连接的两条边的方向设为相同的,比如上图中, 8 8 8 是唯一一个 2 2 2 度点,所以把 9 → 8 9\rightarrow 8 98 改为 8 → 9 8\rightarrow 9 89

若没有两度点,就是不可以。

C++ 代码

#include
#define pb push_back
#define mpr make_pair
using namespace std;
const int maxn=200005;
int n;
vector<int> g[maxn];
bool flag=false;
int cg;
vector<pair<int,int> > ans;
void find(int v,int fa,int col){
	for(int x:g[v]){
		if(x!=fa){
			if(col) ans.pb(mpr(x,v));
			else ans.pb(mpr(v,x));
			find(x,v,col^1);
		}
	}
}
void solve(){
	flag=false; cg=0;
    for(int i=1;i<=n;i++){
		g[i].clear();
	}
    
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].pb(v);
		g[v].pb(u);
	}
    for(int i=1;i<=n;i++){
        if(g[i].size()==2){
            cg=i;
            flag=true;
            break;
        }
    }
    
	if(!flag){
		cout<<"NO\n";
		return;
	}
    
	cout<<"YES\n";
	int prv=g[cg][0],nxt=g[cg][1];
	ans.clear();
	ans.pb(mpr(prv,cg));
	ans.pb(mpr(cg,nxt));
	find(prv,cg,0);
	find(nxt,cg,1);
	for(pair<int,int> x:ans){
		cout<<x.first<<" "<<x.second<<endl;
	}
}

int main(){
	int T;
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

你可能感兴趣的:(Codeforces,题解,Codeforces,C++,STL,算法,图论)