Codeforces Round 885 (Div. 2) A-D

发布时间 2023-07-17 16:04:22作者: HikariFears

A. Vika and Her Friends

题意:有一个n*m大小的矩阵,vika在点(a,b),她的k个朋友在分别(xi,yi),所有人每分钟都可以上下左右走一格,每一分钟vika先走,她的朋友后走,不能不走,问vika能否躲过朋友。

Solution

结论题,只要有一个朋友和她的距离是奇数,那么她肯定会被追上。

void solve()
{
	int n,m,k;cin>>n>>m>>k;
	int a,b;cin>>a>>b;
	//cout<<n<<" "<<m<<" "<<k<<"\n";
	//cout<<a<<" "<<b<<"\n";
	int flag=0;
	for(int i=1;i<=k;i++)
	{
		int x,y;
		cin>>x>>y;
		if(flag==1)
		{
			continue;
		}
		if((abs(x-a)+abs(y-b))%2==0)
		{
			cout<<"NO\n";
			flag=1;
		}
	}
	if(flag==1)return;
	cout<<"YES\n";
	
}

B. Vika and the Bridge

题意:vika给一个由n块木板组成的桥用k种颜色进行了涂刷,每一块木板都有对应的颜色,现在油漆还没有干,她现在想要走过桥但是最多只能改变一个木板的颜色,vika最少需要横跨几个木板走一步才能过桥。

Solution

预处理出只走每种颜色木板需要横跨的最大距离和第二大距离,只改变一个木板的颜色可以让最大距离除以2向下取整,然后遍历每种颜色取最小即可

int a[N]; //第i块木板的颜色
int b[N]; //第i种颜色的最大距离
int c[N]; //第i种颜色木板的上一个位置
int d[N]; //第i种颜色木板的第二大距离
void solve()
{
	int n,k;cin>>n>>k;
	for(int i=1;i<=k;i++)
	{
		b[i]=-1;
		c[i]=-1;
		d[i]=-1;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(b[a[i]]==-1)
		{
			b[a[i]]=i-1;
			c[a[i]]=i;
			//d[a[i]]=i-1;
		}
		else 
		{
			int len=i-c[a[i]]-1;
			if(d[a[i]]==-1)
			{
				if(len>=b[a[i]])
				{
					d[a[i]]=b[a[i]];
					b[a[i]]=len;
				}else
				{
					d[a[i]]=len;
				}
			}else
			{
				if(len>=b[a[i]])
				{
					d[a[i]]=b[a[i]];
					b[a[i]]=len;
				}else if(len>=d[a[i]])
				{
					d[a[i]]=len;
				}
			}
			c[a[i]]=i;
		}
	}
	for(int i=1;i<=k;i++)
	{
		if(b[i]==-1)continue;
		int len=n-c[i];
			if(d[i]==-1)
			{
				if(len>=b[i])
				{
					d[i]=b[i];
					b[i]=len;
				}else
				{
					d[i]=len;
				}
			}else
			{
				if(len>=b[i])
				{
					d[i]=b[i];
					b[i]=len;
				}else if(len>=d[i])
				{
					d[i]=len;
				}
			}
	}
	int ans=INF;
	for(int i=1;i<=k;i++)
	{
		if(b[i]==-1)continue;
		ans=min(ans,max(d[i],b[i]/2));
		//cout<<d[i]<<" "<<b[i]<<"\n";
		//cout<<ans<<" ";
	}
	cout<<ans<<"\n";
}

C. Vika and Price Tags

题意:有两个数组a和b,每次操作可以生成一个新数组c,其中

\[c[i]=|a[i]-b[i]| \]

在此之后令数组b改名变为a,数组c改名变为数组b,是否能进行若干次操作,使得a在某一个时刻变为全0

Solution

首先,如果a[i]=0并且b[i]=0,那么a[i]会一直为0,

其次,如果a[i]!=0并且b[i]!=0,那么最后a[i]和b[i]中间一定有一个在某一时刻会变为0

最后,如果a[i]和b[i]当中有一个是0,另一个不是0

假设a[i]=0,b[i]=x

那么最后它会以(0,x),(x,x),(x,0),(0,x)...循环下去

所以我们需要找到a[i]第一次为0的时刻,并且模三,如果所有a[i]为0的时刻在模三下是相同的,那么可以成立,反之不行。

假设a[i]比b[i]大(如果小那么就进行一次操作)

那么a[i]和b[i]会在若干次操作后变为a[i]%b[i]和b[i],操作次数取决于cnt=a[i]/b[i]的奇偶性,可以发现

如果是偶数,那么会依次进行1 2 1 2 1 2...1 2 1 2 1 2次操作

即(cnt-1)*3/2次操作

其中a[i]会变成b[i]

如果是奇数,那么会依次进行1 2 1 2 1 2...1 2 1 2 1次操作

即1+(cnt-1)*3/2次操作

其中b[i]会变成b[i]

之后用set统计即可

void solve()
{
	int n;cin>>n;
	
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)cin>>b[i];
	
	for(int i=1;i<=n;i++)
	{
		int x=a[i],y=b[i];
		int res=0;
		
		while(x!=0)
		{
			if(y==0)
			{
				res++;
				break;
			}
			if(x<y)
			{
				int temp=abs(x-y);
				x=y;
				y=temp;
				res++;
			}
			int cnt=x/y;
			if(cnt&1)
			{
				int temp=x%y;
				x=y;
				y=temp;
				res+=1+(cnt-1)*3/2;
			}else
			{
				int temp=x%y;
				x=temp;
				res+=(cnt*3)/2;
			}
		}
		c[i]=res;
		
	}
	set<int>st;
	for(int i=1;i<=n;i++)
	{
		if(a[i]==0&&b[i]==0)continue;
		st.insert(c[i]%3);
		//cout<<c[i]<<" \n"[i==n];
	}
	cout<<((st.size()<=1)?"YES\n":"NO\n");
}

D. Vika and Bonuses

题意:最开始有一个数s,答案最开始是0,可以进行以下两种操作共计最多k次,

1.使答案加上s

2.使s加上s的个位的数

问最后答案最大是多少

Solution

易发现,如果一直进行操作2,个位上会出现2 4 8 6的循环,那么我们可以发现

\[ans=(s+20x)*(k-4x) \]

这是一个抛物线,平分线为(5k-s)/40,直接把个位上是2 4 8 6的每种情况都算一遍,最后取最大值即可

注意如果个位上是5则最多进行一次操作2

并且个位上是奇数时需要先进行一次操作2然后再进行才能进入循环

//0
//1 2 4 8 6
//2 4 8 6
//3 6 2 4 8 6
//4 8 6 2 4 8 6
//5 0
//6 2 4 8 6
//7 4 8 6 2 4 8 6
//8 6 2 4 8 6
//9 8 6 2 4 8 6
 
int check(int s,int k)
{
	int mid=(5*k-s)/40;
	int x=min(mid,k/4);
	int res=s*k;
	if(x>0)res=max(res,(s+20*x)*(k-4*x));
	x=min(x+1,k/4);
	if(x>0)res=max(res,(s+20*x)*(k-4*x));
	return res;
}
 
void solve()
{
	int s,k;cin>>s>>k;
	int ans=0;
	int cnt=s%10;
	if(cnt==5)
	{
		cout<<max(s*k,(s+5)*(k-1))<<"\n";
		return;
	}else if(cnt==0)
	{
		cout<<s*k<<"\n";
		return;
	}
	ans=s*k;
	if(cnt&1)
	{
		ans=max(ans,(s+cnt)*(k-1));
		s+=cnt;k--;
	}
	for(int i=0;i<4;i++)
	{
		//cout<<s<<" "<<k<<" "<<check(s,k)<<"\n";
		if(k>0)ans=max(ans,check(s,k));
		s+=s%10;
		k--;
	}

	cout<<ans<<"\n";
}