Educational Codeforces Round 169 (Rated for Div. 2)(ABCDE)

 A. Closest Point

签到

#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
int n,m;
int q[N];
void solve()
{
	cin>>n;
	_rep(i,1,n)cin>>q[i];
	if(n!=2)cout<<"NO\n";
	else if(abs(q[1]-q[2])!=1)cout<<"YES\n";
	else cout<<"NO\n";
	return ;
}

B. Game with Doors

题意:已知房间和房间初始之间没有门,加门之后房间和房间之间就相互不连通,给定两个区间[l,r],[L,R],问至少加多少扇门可以使得区间各自选一个点,这两个点一定不连通

手玩几个例子就可以发现

给定的区间没有交集的时候用一个门隔断即可

有交集的话交集(假设大小为x)内部的门一定要选上也就是x-1

然后就是边界,假设左端点不同那么左端点靠右的左边还要额外加一扇门,右端点同理

void solve()
{
	int a,b,c,d;
	cin>>a>>b>>c>>d;
	int x=max(a,c),y=min(b,d);
	if(a==c&&b==d)cout<<b-a<<'\n';
	else if(x>y)cout<<"1\n";
	else 
	{
		int res=0;
		if(a!=c)res++;
		if(b!=d)res++;
		cout<<y-x+res<<'\n';
	}
	return ;
}

C. Splitting Items

A,B玩家玩游戏,n个物品都有成本,从A开始轮流拿,假设A一共拿的成本为a,B一共拿的成本为b,那么A要使a-b最大化,B要使a-b最小化,现在B可以加k个成本(k可以分配给任意物品),问最终a-b最小值

思路:假设B不能加成本,A,B显然每次都拿最大值,那么从大到小排序,(编号从1开始比)A拿奇数位,B拿偶数位即可,现在B可以偷偷加成本,那么显然肯定是贪心的拿每个偶数位加成本,但是不能超过前一个奇数位,因为超过的话这一位排序之后就比前一个大了所以排在前一个前面,所以这一位反而变成了奇数位,所以最终偶数位加成本不超过前一个奇数位即可

代码实现:


#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
int n,m,k;
int q[N];
void solve()
{
	cin>>n>>k;
	_rep(i,1,n)cin>>q[i];
	sort(q+1,q+1+n,greater<>());
	int a=0,b=0;
	for(int i=1;i<=n;i+=2)
	{
		a+=q[i];
		if(i+1<=n)
		{
			b+=q[i+1]+min(q[i]-q[i+1],k);
			k-=min(q[i]-q[i+1],k);
		}
	}
	cout<<a-b<<"\n";
	return ;
}

D. Colored Portals

题意:每一个点对应两个字母,然后点与点之间如果有一个字母相同则可以连一条无向边,权重为两个点下标之差,给定n个点,m次询问,每次询问两个点的下标,要求找到两个点之间的最短路,如果没有则输出-1

思路:一共只有四个字母假设为,可以发现询问的时候只要两个点有一个相同字母,则最短路肯定是两个点直接连边,否则要找一个中转站,两点通过中转站连接,这个中转站显然只要满同不等于a点的两个字母和b点对应的两个字母,其实也相当于这个中转站的字母组成就是a点两个字母取一个,b点两个字母取一个,那就一定能满足题目连边的条件起到中转的目的,为了实现路径最短,显然要在a点左边和右边分别找到第一个中转站或者在b点左边和b点右边找一个中转站,假设坐标为x,那么最短路长度就是abs(b-x)+abs(a-x),实际上最麻烦的点在于:假设要找"BG" 如何找到当前坐标前面第一个"BG”和后面第一个"BG",那么把所有6种字母组合从1~6编号,然后求pre数组和next数组的时候遍历6个编号即可,具体实现在下面代码里体现

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18;
int n,m;
int qian[7][N];
string s[N];
int id[255];
int get(char a,char b)//编号
{
	if(id[a]>id[b])swap(a,b);
	if(id[a]==1)return id[b]-1;
	else if(id[a]==2)return id[b]+1;
	else return 6ll;
}
void init()
{
	id['B']=1;
	id['G']=2;
	id['R']=3;
	id['Y']=4;
}
int pre[N][10],ne[N][10];//pre[i][j]表示i位置第j个字符串的编号(假设为"BG")的前面第一个"BG"的位置
void solve()
{
	cin>>n>>m;
	_rep(i,1,n)
	cin>>s[i];
	int now[10];
	_rep(i,1,6)now[i]=0;
	_rep(i,1,n)
	{	
		_rep(k,1,6)
			pre[i][k]=now[k];
		now[get(s[i][0],s[i][1])]=i;
	}
	_rep(i,1,6)now[i]=n+1;
	_pre(i,n,1)
	{
		_rep(k,1,6)
			ne[i][k]=now[k];
		now[get(s[i][0],s[i][1])]=i;
	}
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		if(a>b)swap(a,b);
		int res=INF;
		for(auto i:s[a])
			for(auto j:s[b])
			{
				if(i==j)res=b-a;
				else
				{
					int now=get(i,j);
					if(pre[a][now])
						res=min(res,abs(a-pre[a][now])+abs(b-pre[a][now]));
					if(pre[b][now])
						res=min(res,abs(a-pre[b][now])+abs(b-pre[b][now]));
					if(ne[b][now]!=n+1)
						res=min(res,abs(a-ne[b][now])+abs(b-ne[b][now]));
//					if(ne[a][now]!=n+1)//这里没必要了因为如果中转点在中间的话那么答案就是b-a,那么前面的pre[b][now]显然可以遍历到
//						res=min(res,abs(a-ne[a][now])+abs(b-ne[a][now]));
				}
			}
		if(res==INF)cout<<"-1\n";
		else cout<<res<<'\n';
	}
	return ;
}
signed main()
{
	IOS;
	init();
	int T=1;
	cin>>T;
	while(T--)
		solve();
	return 0;
}

E. Not a Nim Problem

题意,Alice和Bob做游戏,一共给定n堆石子,A先开始,每次可以从一堆石子(假设为y)中拿掉一部分(假设为x),那么一定要保证gcd(x,y)=1,最后轮到谁没有石子了谁就输了,对方就赢了

显然要用到NIM游戏的结论,所以现在要求的就是输入规模1~1e7的每一个数字的sg值

首先看一下一堆石子假设为x,那么x能走到哪些点?

首先x在满足gcd(x,y)==1的时候拿掉y个石子的所有情况构成了一个集合,可以发现和拿掉之后剩余石子x-y构成的集合一定是一样的,因为剩余的石子x-y一定也满足gcd(x,y)==1,为什么?假设gcd(x,y)=z那么x和y一定都是z的倍数(假设x=a*z,y=b*z,a>b并且gcd(a,b)=1),那么x-y=(a-b)*z,显然可以发现gcd(x,x-y)=z(因为a,b是互质所以a,a-b也互质,PS:假设a,a-b不互质那么a,a-(a-b);也就是a.b不互质与a,b互质矛盾,所以a,a-b必定互质))

现在就可以画图找规律了

手玩以下可以发现(黑色点为石子数量,红色为sg值)

1.sg[1]=0

2.石子数量为偶数时候走不到任何sg值为0的点,所以sg[偶数]=0

举个例子,现在当前只知道sg[0~5],发现sg[2]=sg[4]=0,sg[0]就不管了因为只有1能走到0,那么我现在要求sg[6],要使得6走到sg值为0的点那就只能走到2,4但是两个偶数的gcd肯定不会为1

3.sg[质数]=质数在质数序列中的编号,比如sg[3]=2,sg[5]=3,可以发现sg[x]能走到的最大sg值是sg[x‘

],x'为这个质数的上一个质数,所以sg[x]=sg[x']+1

4.对于其他的x,sg[x]=sg[x''],其中x''为x的最小质因数

看上面的图中的9,他的最小质因数是3,首先这个9至少能达到sg[3]-1(也就是sg[9]=sg[3]),因为3是它的质因数,所以它同样可以走到相对于3的所有能走到的点。

然后看一下9能否走到sg[3]?(为什么突然要看这个点呢,因为图中的9走不到sg[3]所以看一下这种情况是不是必然的)看一下sg[3]为什么为sg[3],是因为3这个数可以走到0,1这两个状态(注意是状态(sg值)而不是石子数量)而走不到2这个状态,还有哪些数能满足这个性质?很显然可以发现只要以3为质因数的数字都满足这个性质,回到这一段开始的问题,可以发现要走到sg[3]一定要走到以3为质因数的数字,但是9不可能走到3为质因数的数字因为9和这个数字都是3的倍数,不满足题目要求,所以说9可以走到的状态一定断在了sg[3],那么就可以得到sg[9]=sg[3]

代码实现

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e7+10,INF=4e18;
int n,m;
int prime[N],cnt,sg[N],minprime[N];
bool st[N];
void init()
{
	for(int i=2;i<N;i++)
	{
		if(!st[i])prime[cnt++]=i;
		for(int j=0;prime[j]*i<N;j++)
		{
			st[prime[j]*i]=true;
			minprime[prime[j]*i]=prime[j];
			if(i%prime[j]==0)break;
		}
	}
	for(int i=0;i<cnt;i++)
		sg[prime[i]]=i+1;
	return;
}
void solve()
{
	cin>>n;
	int res=0;
	while(n--)
	{
		cin>>m;
		if(m%2==0)m=2;
		else if(st[m])m=minprime[m];
		res^=sg[m];
	}
	if(res)cout<<"Alice\n";
	else cout<<"Bob\n";
	return ;
}
signed main()
{
	IOS;
	int T=1;
	cin>>T;
	init();
	sg[1]=1;
	sg[2]=0;
	while(T--)
		solve();
	return 0;
}

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值