Label
EXCRT+二分答案
Description
原题链接:https://codeforces.com/problemset/problem/1500/B
抽象题意:给定长度分别为 n , m n,m n,m的、序列内元素互不相同的两个不同的正整数序列 a , b a,b a,b与正整数 k k k,求最小的正整数 q q q,满足:
∑ i = 1 q [ a ( ( i − 1 ) m o d n + 1 ) ≠ b ( ( i − 1 ) m o d n + 1 ) ] ≥ k \sum_{i=1}^{q}[a_{_{((i-1)modn+1)}}\ne b_{_{((i-1)modn+1)}}]\ge k i=1∑q[a((i−1)modn+1)=b((i−1)modn+1)]≥k
其中 1 ≤ n , m ≤ 5 × 1 0 5 , 1 ≤ k ≤ 1 0 12 , 1 ≤ a i , b i ≤ 2 × m a x ( n , m ) 1\leq n,m\leq5\times 10^5,1\leq k\leq 10^{12},1\leq a_i,b_i\leq 2\times max(n,m) 1≤n,m≤5×105,1≤k≤1012,1≤ai,bi≤2×max(n,m).
Solution
由于只有存在 a i = b j a_i=b_j ai=bj的情况下才会对答案发生影响( a i ≠ b j a_i\neq b_j ai=bj时,其对给定 ∑ \sum ∑的贡献一定为 0 0 0),故对于任意一个 ∈ a \in a ∈a的元素 a i a_i ai,我们只需考虑其是否在 b b b内也出现过(设其为 b j b_j bj);如果出现过,是否会出现 a ( ( i − 1 ) m o d n + 1 ) = b ( ( i − 1 ) m o d n + 1 ) a_{_{((i-1)modn+1)}}=b_{_{((i-1)modn+1)}} a((i−1)modn+1)=b((i−1)modn+1)的情况。
假设
i
=
x
i=x
i=x满足上式,那么一定有:
{
x
≡
i
(
m
o
d
n
)
x
≡
j
(
m
o
d
m
)
\begin{cases}x\equiv i(modn)\\x\equiv j(modm)\end{cases}
{x≡i(modn)x≡j(modm)
其中 i , j i,j i,j分别为 a i a_i ai在数列 a , b a,b a,b的位置下标。
有了这个东西,我们便可以利用EXCRT(其实两个方程可以直接利用求EXCRT的原理进行EXGCD推导)求出所有 x x x的通解形式,进而得出两盏灯颜色同为 a i a_i ai(见原题题意)的所有时刻。
至于求 q q q的方法,由于 q q q越大越容易满足给定条件,故我们直接进行答案越小越优的二分答案即可(此题答案不会爆long long)。在二分答案的check函数里,当 q = m i d q=mid q=mid时,我们枚举所有 a i a_i ai,利用之前求得的 x i x_i xi,计算第 1 ∼ q 1\sim q 1∼q天内两盏灯颜色同为 a i a_i ai的天数 d i d_i di,最后直接将 m i d − ∑ i = 1 n d i mid-\sum_{i=1}^{n}d_i mid−∑i=1ndi与 k k k比较即可。 > k >k >k则说明最优答案 ≤ m i d \leq mid ≤mid,反之则大于。
复杂度: O ( n l o g V ) O(nlogV) O(nlogV),其中 V V V为可能的最大答案(此题的复杂度来源于二分答案,由于EXGCD可以只进行一次,所以整个求 x i x_i xi的过程复杂度为 O ( n ) O(n) O(n))。
Code
#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;
const int MAXN=1e6+20;
int N,M,cola[MAXN],colb[MAXN];
ll K,plaa[MAXN<<1],plab[MAXN<<1],ans[MAXN],A,B,Mi,G,C,x,y,xi,yi,l,r,mid,nowsame;
ll Gcd(ll a,ll b) { return ((b==0)?a:Gcd(b,a%b)); }
ll Lcm(ll a,ll b) { return (a/Gcd(a,b))*b; }
ll Msc(ll a,ll b,ll MOD)
{
ll tot=0;
for(;b;b>>=1,a=(a+a)%MOD)
if(b&1) tot=(tot+a)%MOD;
return tot;
}
void Exgcd(ll a,ll b)
{
if(b==0) { x=1,y=0; return; }
Exgcd(b,a%b);
xi=x,yi=y;
x=yi,y=xi-(a/b)*yi;
}
bool check(ll tot)
{
nowsame=0;
for(ri i=1;i<=N;++i)
{
if(ans[i]==0||ans[i]>tot) continue;
nowsame+=1+(tot-ans[i])/Mi;
}
if(tot-nowsame>=K) return true;
return false;
}
int main()
{
scanf("%d%d%lld",&N,&M,&K);
for(ri i=1;i<=N;++i)
{
scanf("%d",&cola[i]);
plaa[cola[i]]=(ll)i;
}
for(ri i=1;i<=M;++i)
{
scanf("%d",&colb[i]);
plab[colb[i]]=(ll)i;
}
Mi=Lcm(N,M);
Exgcd(N,M);
for(ri i=1;i<=N;++i)
{
if(plab[cola[i]]==0LL) continue;
ans[i]=plaa[cola[i]]; C=plab[cola[i]]-ans[i]; G=Gcd(N,M);
if(C%G!=0) { ans[i]=0; continue; }
x=(x%(M/G)+(M/G))%(M/G);
ans[i]=(ans[i]+Msc((C/G)%Mi,Msc(N,x,Mi),Mi))%Mi;
if(ans[i]>0) ans[i]%=Mi;
if(ans[i]<0) ans[i]=(ans[i]%Mi+Mi)%Mi;
if(ans[i]==0) ans[i]=Mi;
}
l=1,r=1e18;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
if(check(l)) cout<<l;
else cout<<"-1";
return 0;
}