CF1501D Two chandeliers【拓展欧几里得+二分】

题意

给两个数组 ab ,长度分别为 \(n\),\(m\),每个数组中不含相同的数,且各自不断循环,问第 \(k\) 次不同是在第几天。\((1≤n,m≤5\times10^5;1≤k≤10^{12},1≤a_i,b_i≤2⋅\max(n,m))\)。题目链接:https://codeforces.com/contest/1501/problem/D

分析

假设 a 数组中 \(a_i\)b 数组中 \(b_j\) 相等,那么可以列出方程:\(xn+i=ym+j\) 。如果方程有解,说明有很多天,\(a_i\)\(b_j\) 是相等的且处于同一天。否则,表示二者不可能出现在同一天。对每个数都统计完之后,只有这些数会对第 \(k\) 次不同出现的天数产生影响。用数字存下这些数在 \(lcm(n,m)\) 天内,同时出现是在哪一天,每一个 \(lcm\) 为一个周期,出现一次。之后,采用二分的方式求解,具体见代码(二分边界要大些)。

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=5e5+5;
int a[N],b[N],pos[N<<1],cnt;
ll lcm,k,num[N];//num[N]开成了int型,但没有re,而是wa
int gcd(int x,int y)
{
	return y==0?x:gcd(y,x%y);
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	ll res=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return res;
}
ll cal(ll a,ll b,ll c,ll d)//n,-m,
{
	ll e=d-c;
	ll x=0,y=0;
	ll gcd=exgcd(a,b,x,y);
	if(e%gcd) return -1;
	x=e/gcd*x;
	if(b<0) b=-b;
	b/=gcd;
	x=(x%b+b)%b;//最小正整数解
	ll ans=x*a+c;
	return ((ans-1)%lcm+lcm)%lcm+1;//在一个lcm内
	//WA:(ans-1)%lcm+1
}
bool check(ll mid)
{
	ll res=0;
	for(int i=1;i<=cnt;i++)
		//if(mid>=num[i]) res+=((mid-num[i])/lcm+1);
		res+=(mid/lcm+((mid%lcm)>=num[i]));//
	return (mid-res>=k);
}
int main()
{
    int n,m;
    scanf("%d%d%lld",&n,&m,&k);
    lcm=1LL*n*m/gcd(n,m);
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&a[i]);
    	pos[a[i]]=i;
    }
    cnt=0;
    for(int i=1;i<=m;i++) 
    {
    	scanf("%d",&b[i]);
    	if(pos[b[i]]>0)
    	{
    		ll res=cal(1LL*n,-1LL*m,1LL*pos[b[i]],1LL*i);cout<<"res="<<res<<endl;
    		if(res!=-1) num[++cnt]=res; 
    	}
    }
    ll l=1,r=1e18;
    while(l<=r)
    {
    	ll mid=(l+r)>>1;
    	if(check(mid)) r=mid-1;
    	else l=mid+1;
    }
    printf("%lld\n",l);
    return 0;
}

posted @ 2021-03-15 16:51  xzx9  阅读(177)  评论(0编辑  收藏  举报