Educational Codeforces Round 169 A-E题解

全场评价:手速场
A
题意:
在这里插入图片描述
做法:首先如果超过了两个数,那一定不可可以实现新放的数与所有数距离都最近。如果只有两个数,只需要把新数放在两者之间就可以,注意特判两数距离为1,此时两数之间无法放入新数。
c o d e : code: code:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int N = 105;
int t;
int a[N];
int n,m,h,w;
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		if(n==2&&(fabs(a[1]-a[2])!=1))
		{
			printf("YES\n");
		}
		else printf("NO\n");
	}
	return 0;
}

B
题意:
在这里插入图片描述
做法:
发现答案应该大致取在两个区间的交集上。如果两个区间不相交答案肯定是1。
再仔细想一想,如果交集的区间边界跟两个区间的边界都不重合,那应该是交集的区间再加上该区间前后各一扇门。如果交集的区间边界与给定两个区间的某一个边重合,那只需要加上没重合的那个边界旁边的一扇门。如果交集的区间边界与两个区间的边界都重合,那就不需要再额外扩展交集区间。
如图,蓝区间是交集区间,红黑是给定初始区间,设总答案为蓝区间长度+2,如果蓝区间的某一条边与红或者黑相交,答案就要减去1,两个边都相交,答案就减去2。
在这里插入图片描述
c o d e : code: code:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int N = 1;
int t;
int l,r,R,L;
int n,m,h,w;
int main()
{
	cin>>t;
	while(t--)
	{
		scanf("%d%d%d%d",&l,&r,&L,&R);
		if(r<L||R<l)//不相交
		{
			printf("1\n");
			continue ;
		}
		int lr=max(l,L);//左边界
		int rr=min(r,R);//右边界
		int ans=rr-lr+2;
		if(l==L) ans--;//左边界重合
		if(r==R) ans--;//右边界重合
		printf("%d\n",ans);
	}
	return 0;
}

C
题意:
在这里插入图片描述
做法:不要被Alice&Bob唬住了,这个题和博弈论没啥关系。
发现两者每次操作一定是拿当前剩余数中最大的那个数。
具体来说,数列确定后,爱丽丝拿的一定是数列第1,3,5,,,2k-1大的数,鲍勃拿的一定是数列第2,4,6,2k大的数。最终得分就是让两个人拿的数两两做差,爱丽丝拿的第 i i i个数和鲍勃拿的第 i i i个数做差,所有的差全部加起来就是最终得分。
那么我们可以把鲍勃拿到的数逐个增大,尽可能让鲍勃拿的前 m m m个数与爱丽丝拿的前 m m m个数一样大,这样一定把贡献都给了鲍勃。
c o d e : code: code:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#define int long long
using namespace std;
const int N = 2e5+5;
int t;
int a[N];
int k;
int n,m,h,w;
bool cmp(int a,int b)
{
	return a>b;
}
signed main()
{
	cin>>t;
	while(t--)
	{
		scanf("%lld%lld",&n,&k);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		sort(a+1,a+1+n,cmp);//排序 
		for(int i=1;i<=n;i+=2)
		{
			if(i>n) break;
			if(i==n&&n%2) break;
			if(k==0) break;
			int cnt=a[i]-a[i+1];
			if(k>=cnt)
			{
				k-=cnt;
				a[i+1]=a[i];//让bob的数和Alice的一样大 
			}
			else
			{
				a[i+1]+=k;//全部加到bob的数上 
				break;
			}
		}
		int ans=0;
		for(int i=1;i<=n;i+=2)
		{
			if(i>n) break;
			ans+=a[i]-a[i+1];
		}
		for(int i=1;i<=n;i++) a[i]=0;//注意多测清空!我这里没清空挂了一次 
		printf("%lld\n",ans);
	} 
	return 0;
}

D
题意:在这里插入图片描述
数据范围: n , q < = 2 ∗ 1 0 5 n,q<=2*10^5 n,q<=2105
做法:
赛时想到一种好想不好写的做法。不需要用二分或者数据结构。

首先,不难发现 x x x y y y的最优路径应该是 x x x一步传送到 y y y。此时 x x x y y y至少有一个字母是相同的。
如果 x x x不能一步传送到 y y y,则 x x x y y y一定形如 x : A B x:AB x:AB y : C D y:CD y:CD
那么可以从 x x x传到 z 1 z_1 z1,再从 z 1 z_1 z1传到 y y y。此时 z 1 : A C o r A D o r B C o r B D z_1:AC orADorBCorBD z1:ACorADorBCorBD;
或者从 y y y传送到 z 2 z_2 z2,再从 z 2 z_2 z2传送到 x x x。此时 z 2 : A C o r A D o r B C o r B D z_2:ACorADorBCorBD z2:ACorADorBCorBD;

那么对于任意一个 i : A B i:AB i:AB
我们只需要统计他前面最近的 j 1 : A C o r A D o r B C o r B D j_1:AC orADorBCorBD j1:ACorADorBCorBD
以及他后面最近的 j 2 : A C o r A D o r B C o r B D j_2:AC orADorBCorBD j2:ACorADorBCorBD
对于每个 i i i,分别统计这两个最短距离。我们维护每种可能的字符组合的出现位置(一共六种可能的字符)

每次询问 x x x y y y时,若 x x x能直接到 y y y,答案就是 ∣ x − y ∣ |x-y| xy。否则答案为
m i n [ d i s ( x − > z 1 − > y ) , d i s ( y − > z 2 − > x ) ] min[dis(x->z_1->y),dis(y->z_2->x)] min[dis(x>z1>y),dis(y>z2>x)]

注意一个易错的地方,那就是 z 1 z_1 z1 z 2 z_2 z2有可能出现在 x x x y y y之间。不要认为 z 1 z_1 z1 z 2 z_2 z2一定出现在 x x x y y y的区间之外
c o d e : code: code:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <unordered_map>
using namespace std;
const int N = 2e5+5;
int t;
int n,q;
string s[N];
int qian[N],hou[N];
bool check(int l,int r)
{
	char a=s[l][0];char b=s[l][1];char c=s[r][0];char d=s[r][1];
	if(a==c||a==d||b==c||b==d) return 1;
	else return 0;
}
int main()
{
	cin>>t;
	while(t--)
	{
		
		scanf("%d%d",&n,&q);
		int hd1=0;int hd2=0;int hd3=0;int hd4=0;int hd5=0;int hd6=0;
		int la1=n+1;int la2=n+1;int la3=n+1;int la4=n+1;int la5=n+1;int la6=n+1;
		for(int i=1;i<=n;i++) hou[i]=n+1,qian[i]=0;
		for(int i=1;i<=n;i++)
		{
			cin>>s[i];			
			if((s[i][0]=='B'&&s[i][1]=='G')||(s[i][0]=='G'&&s[i][1]=='B'))
			{
				hd1=i;
				qian[i]=max(max(max(hd2,hd3),hd4),hd5);
			}
			if((s[i][0]=='B'&&s[i][1]=='R')||(s[i][0]=='R'&&s[i][1]=='B'))
			{
				hd2=i;
				qian[i]=max(max(max(hd1,hd3),hd4),hd6);
			}
			if((s[i][0]=='B'&&s[i][1]=='Y')||(s[i][0]=='Y'&&s[i][1]=='B'))
			{
				hd3=i;
				qian[i]=max(max(max(hd1,hd2),hd6),hd5);
			}
			if((s[i][0]=='G'&&s[i][1]=='R')||(s[i][0]=='R'&&s[i][1]=='G'))
			{
				hd4=i;
				qian[i]=max(max(max(hd1,hd5),hd6),hd2);
			}			
			if((s[i][0]=='G'&&s[i][1]=='Y')||(s[i][0]=='Y'&&s[i][1]=='G'))
			{
				hd5=i;
				qian[i]=max(max(max(hd1,hd3),hd4),hd6);
			}
			if((s[i][0]=='R'&&s[i][1]=='Y')||(s[i][0]=='Y'&&s[i][1]=='R'))
			{
				hd6=i;
				qian[i]=max(max(max(hd2,hd3),hd4),hd5);
			}
		}
		for(int i=n;i>=1;i--)
		{			
			if((s[i][0]=='B'&&s[i][1]=='G')||(s[i][0]=='G'&&s[i][1]=='B'))
			{
				la1=i;
				hou[i]=min(min(min(la2,la3),la4),la5);
			}
			if((s[i][0]=='B'&&s[i][1]=='R')||(s[i][0]=='R'&&s[i][1]=='B'))
			{
				la2=i;
				hou[i]=min(min(min(la1,la3),la4),la6);
			}
			if((s[i][0]=='B'&&s[i][1]=='Y')||(s[i][0]=='Y'&&s[i][1]=='B'))
			{
				la3=i;
				hou[i]=min(min(min(la1,la2),la6),la5);
			}
			if((s[i][0]=='G'&&s[i][1]=='R')||(s[i][0]=='R'&&s[i][1]=='G'))
			{
				la4=i;
				hou[i]=min(min(min(la1,la2),la6),la5);
			}			
			if((s[i][0]=='Y'&&s[i][1]=='G')||(s[i][0]=='G'&&s[i][1]=='Y'))
			{
				la5=i;
				hou[i]=min(min(min(la1,la3),la4),la6);
			}
			if((s[i][0]=='R'&&s[i][1]=='Y')||(s[i][0]=='Y'&&s[i][1]=='R'))
			{
				la6=i;
				hou[i]=min(min(min(la2,la3),la4),la5);
			}
		}
		for(int i=1;i<=q;i++)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			if(l>r) swap(l,r);
			if(l==r)
			{
				printf("0\n");
				continue ;
			}
			if(check(l,r))
			{
				printf("%d\n",(r-l));
				continue ;
			}
			else
			{
				if(hou[l]==n+1&&qian[l]==0&&qian[r]==0&&hou[r]==n+1)
				{
					printf("-1\n");
					continue ;
				}
				else if(hou[l]<=r||qian[r]>=l)
				{
					printf("%d\n",r-l);
				}
				else
				{
					int cnt=0x3f3f3f3f;
					if(hou[l]!=n+1) cnt=min(cnt,hou[l]-l);
					if(hou[r]!=n+1) cnt=min(cnt,hou[r]-r);
					if(qian[l]!=0) cnt=min(cnt,l-qian[l]);
					if(qian[r]!=0) cnt=min(cnt,r-qian[r]);
					int ans=fabs(r-l)+cnt*2;
					printf("%d\n",ans);
				}
			}
		}
	}
	return 0;
}

E
题意:
在这里插入图片描述
做法:
发现是标准的 S G SG SG问题,先打个表找一下 S G SG SG函数的规律。
在这里插入图片描述
发现所有偶数的 S G SG SG函数值为 0 0 0,第 k k k个质数的 S G SG SG函数值就是 k k k。合数 x x x S G SG SG函数值就是 x x x的最小质因数的 S G SG SG函数值。

只需要用筛子筛一遍素数,顺带就把 S G SG SG函数都求出来了。

证明:我不会

c o d e : code: code:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int maxn = 3e5+5;
const int N = 1e7+5;
int t;
int a[maxn];
int sg[N];
int n,m,h,w;
bool vis[N];
int prim[N];
int head;
int tot;
int is_prime(int x)
{
	for(int i=1;i<=x;i++) vis[i]=1;
	sg[1]=1;
	for(int i=2;i<=x;i++)
	{
		if(vis[i]) 
		{
			prim[++head]=i;
			sg[i]=++tot;//质数的sg函数是依次数下来的 
		}		
		for(int j=1;j<=head&&i*prim[j]<=x;j++)
		{
			vis[i*prim[j]]=0;
			if(sg[i*prim[j]]==0)
			{
				sg[i*prim[j]]=sg[prim[j]];//合数的sg函数是其最小质因子的sg函数 
			}
			if(i%prim[j]==0) break;
		}
	}
	for(int i=1;i<=x;i++) if(i%2==0) sg[i]=0;//偶数的sg函数都是0 
}
int main()
{
	cin>>t;
	is_prime(1e7+2);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		int res=sg[a[1]];
		for(int i=2;i<=n;i++) res^=sg[a[i]];
		if(res) printf("Alice\n");
		else printf("Bob\n");
	}
	return 0;
}
  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值