Codeforces Round #707 (Div. 1, based on Moscow Open Olympiad in Informatics) B. Two chandeliers
Codeforces Round #707 (Div. 2, based on Moscow Open Olympiad in Informatics) D. Two chandeliers
题意
给定两个循环节分别为(n,m)的数组({a})与({b}),这两个数组可以无限循环延伸,在一个循环节中的数字互不相同
现在要从位置(1)开始走,({a})数组第(i)步的值为(a_{(i-1)\%n+1}),({b})数组第(i)步的值为(a_{(i-1)\%m+1})
问一个最小的值(x),使得前(x)步中,(a_{(i-1)\%n+1} eq a_{(i-1)\%m+1})的步数至少为(k)
保证两数组不同(题目一定有解)
限制
(1le n,mle 5cdot 10^5)
(1le kle 10^{12})
(1le a_i,b_ile 2cdot max(n,m))
思路
由于(a_{(i-1)\%n+1} eq a_{(i-1)\%m+1})的步数函数是一个单调非递减的函数
故可以通过二分答案(x)确定这个最小值
因为在一个循环节中的数字互不相同
故对于任意一个可能在某一步相同的数而言,它出现的循环节长度应为(lcm(n,m))
而对于这个数第一次出现的位置(p),假设其在({a})数组中下标为(i),在({b})数组中下标为(j)
可以得到以下两式:
套扩展中国剩余定理即可(由于二分对下标不影响,故这部分需预处理)
其后每次二分check时,只需要枚举一次({a})数组,获取位置(i)的数字(a_i)首次出现的步数(p_i)
那么在前(x)步中,数字(a_i)相等的次数为(lfloor frac{x-p_i}{lcm} floor +1)
求出所有数字相等的次数总和(sum),那么不相等的次数即(x-sum)
检查是否(x-sumge k)即可
代码
(904ms/2000ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll LINF=0x3f3f3f3f3f3f3f3f;
int n,m,a[500050],b[500050],p[1000050];
ll u[5],v[5],x[500050],k,LCM;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b)
d=a,x=1,y=0;
else{
ex_gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
ll ex_crt(ll *m,ll *r,int n){
ll M=m[1],R =r[1],x,y,d;
for(int i=2;i<=n;i++){
ex_gcd(M,m[i],d,x,y);
if((r[i]-R)%d)
return -1;
x=(r[i]-R)/d*x%(m[i]/d);
R+=x*M;
M=M/d*m[i];
R%=M;
}
return R>0?R:R+M;
}
bool check(ll step)
{
ll sum=0;
for(int i=1;i<=n;i++)
{
if(x[i]==-1||step<x[i])
continue;
sum+=(step-x[i])/LCM+1;
}
return step-sum>=k;
}
void solve()
{
cin>>n>>m>>k;
LCM=1LL*n*m/gcd(n,m);
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i],p[b[i]]=i;
for(int i=1;i<=n;i++)
{
if(!p[a[i]]) //a中出现的数在b中未出现
{
x[i]=-1;
continue;
}
u[1]=n,v[1]=i%n; //第i步下标为i%n,将下标n当作下标0即可,下同
u[2]=m,v[2]=p[a[i]]%m;
x[i]=ex_crt(u,v,2);
}
ll l=1,r=LINF;
while(l<=r)
{
ll mid=l+r>>1;
if(check(mid))
r=mid-1;
else
l=mid+1;
}
cout<<l<<'
';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
solve();
return 0;
}