Vika and Price Tags

Link\text{Link}

题意

给定两个长度为 nn 的数组 a1na_{1\sim n}b1nb_{1\sim n},每次可以进行如下操作:

  • 对于每个 i[1,n]i\in[1,n]aiaibia_i\leftarrow |a_i-b_i|
  • 对于每个 i[1,n]i\in[1,n],交换 ai,bia_i,b_i

求多次操作后是否能使所有 bib_i 变成 00

分析

假如 ai=5,bi=3a_i=5,b_i=3,可以发现它们是这样变化的:(5,3)(3,2)(2,1)(1,1)(1,0)(0,1)(1,1)(1,0)(0,1)(5,3)\rightarrow(3,2)\rightarrow(2,1)\rightarrow(1,1)\rightarrow(1,0)\rightarrow(0,1)\rightarrow(1,1)\rightarrow(1,0)\rightarrow(0,1)\rightarrow\dots\dots

(ai,bi)(a_i,b_i) 变成 (x,0)(x,0) 后,它就会开始循环:(x,0)(0,x)(x,x)(x,0)(x,0)\rightarrow(0,x)\rightarrow(x,x)\rightarrow(x,0),循环节为 33,于是我们就可以记录 ci,jc_{i,j} 表示 (ai,bi)(a_i,b_i) 经过 3k+j(kN+)3k+j(k\in N_+) 次操作后,bib_i 能否变成 00,若存在 jj 满足 ci,j(i[1,n])c_{i,j}(i\in[1,n]) 全为 11,那么就可以使所有 bib_i 变成 00

如果直接暴力计算出 bib_ici,jc_{i,j} 的话,肯定会超时,需要优化。我们假设 aia_i 远大于 bib_i,那么 aibia_i-b_i 一定是正的,假设如果连续多次减法都不出现负数的话,变化的过程就是这样的 (ai,bi)(bi,aibi)(aibi,ai2bi)(ai2bi,bi)(bi,ai3bi)(ai3bi,ai4bi)(ai4bi,bi)(bi,ai5bi)(a_i,b_i)\rightarrow(b_i,a_i-b_i)\rightarrow(a_i-b_i,a_i-2b_i)\rightarrow(a_i-2b_i,b_i)\rightarrow(b_i,a_i-3b_i)\rightarrow(a_i-3b_i,a_i-4b_i)\rightarrow(a_i-4b_i,b_i)\rightarrow(b_i,a_i-5b_i)\rightarrow\dots\dots

可以发现从 (bi,aibi)(b_i,a_i-b_i) 开始也有一个类似循环 (bi,ai(2k1)bi)(ai(2k1)bi,ai2kbi)(ai2kbi,bi)(bi,ai(2k+1)bi)(b_i,a_i-(2k-1)b_i)\rightarrow(a_i-(2k-1)b_i,a_i-2kb_i)\rightarrow(a_i-2kb_i,b_i)\rightarrow(b_i,a_i-(2k+1)b_i)。所以我们可以一次性将 (ai,bi)(a_i,b_i) 变为 (bi,ai(2k+1)bi)(b_i,a_i-(2k+1)b_i),即一次性将 aia_i 减去奇数个 bib_i,当然前提是这个差大于 00,最终操作次数会增加 3k+13k+1 步。每次用最大的 kk 来操作,令值域为 SS,复杂度就为 O(nlogS)O(n\log S)

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=1e5+10;
int t,n,a[N],b[N],c[N][3];
int main(){
	t=read();
	while(t--){
		n=read();
		for(int i=1;i<=n;i++){
			a[i]=read();
			c[i][0]=c[i][1]=c[i][2]=0;
		}
		for(int i=1;i<=n;i++){
			b[i]=read();
			c[i][0]=c[i][1]=0;
		}
		int ans1=1,ans2=1,ans3=1;
		for(int i=1;i<=n;i++){
			if(a[i]==0&&b[i]==0){
				c[i][0]=c[i][1]=c[i][2]=1;
			}
			else{
				int u=0,d;
				while(b[i]){
					if(a[i]<=b[i]||a[i]/b[i]<2){
						d=abs(a[i]-b[i]);
						a[i]=b[i];
						b[i]=d;
						u=(u+1)%3;
					}
					else{
						int p=a[i]/b[i],q;
						if((p&1)==0)
							p--;
						u=(u+(p-1)/2*3+1)%3;
						q=a[i]-p*b[i];
						a[i]=b[i];
						b[i]=q;
					}
				}
				c[i][u]=1;
			}
			ans1&=c[i][0];
			ans2&=c[i][1];
			ans3&=c[i][2];
		}
		if(ans1||ans2||ans3)
			puts("YES");
		else
			puts("NO");
	}
	return 0;
}
posted @ 2023-07-17 13:26  luckydrawbox  阅读(5)  评论(0)    收藏  举报  来源