Label
EXCRT+二分答案
Description
原题链接:https://codeforces.com/problemset/problem/1500/B
抽象题意:给定长度分别为n,mn,mn,m的、序列内元素互不相同的两个不同的正整数序列a,ba,ba,b与正整数kkk,求最小的正整数qqq,满足:
∑i=1q[a((i−1)modn+1)≠b((i−1)modn+1)]≥k\sum_{i=1}^{q}[a_{_{((i-1)modn+1)}}\ne b_{_{((i-1)modn+1)}}]\ge ki=1∑q[a((i−1)modn+1)=b((i−1)modn+1)]≥k
其中1≤n,m≤5×105,1≤k≤1012,1≤ai,bi≤2×max(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
由于只有存在ai=bja_i=b_jai=bj的情况下才会对答案发生影响(ai≠bja_i\neq b_jai=bj时,其对给定∑\sum∑的贡献一定为000),故对于任意一个∈a\in a∈a的元素aia_iai,我们只需考虑其是否在bbb内也出现过(设其为bjb_jbj);如果出现过,是否会出现a((i−1)modn+1)=b((i−1)modn+1)a_{_{((i-1)modn+1)}}=b_{_{((i-1)modn+1)}}a((i−1)modn+1)=b((i−1)modn+1)的情况。
假设i=xi=xi=x满足上式,那么一定有:
{x≡i(modn)x≡j(modm)\begin{cases}x\equiv i(modn)\\x\equiv j(modm)\end{cases}{x≡i(modn)x≡j(modm)
其中i,ji,ji,j分别为aia_iai在数列a,ba,ba,b的位置下标。
有了这个东西,我们便可以利用EXCRT(其实两个方程可以直接利用求EXCRT的原理进行EXGCD推导)求出所有xxx的通解形式,进而得出两盏灯颜色同为aia_iai(见原题题意)的所有时刻。
至于求qqq的方法,由于qqq越大越容易满足给定条件,故我们直接进行答案越小越优的二分答案即可(此题答案不会爆long long)。在二分答案的check函数里,当q=midq=midq=mid时,我们枚举所有aia_iai,利用之前求得的xix_ixi,计算第1∼q1\sim q1∼q天内两盏灯颜色同为aia_iai的天数did_idi,最后直接将mid−∑i=1ndimid-\sum_{i=1}^{n}d_imid−∑i=1ndi与kkk比较即可。>k>k>k则说明最优答案≤mid\leq mid≤mid,反之则大于。
复杂度:O(nlogV)O(nlogV)O(nlogV),其中VVV为可能的最大答案(此题的复杂度来源于二分答案,由于EXGCD可以只进行一次,所以整个求xix_ixi的过程复杂度为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;
}