Codeforces Round #707 D.Two chandeliers(二分+扩展中国剩余定理)

题意:

给出两个数组 a a a, b b b,长度分别为 n n n, m m m,第 i i i 时刻, a a a数组当前指向下标为 ( i − 1 ) % n + 1 (i-1) \% n+1 (i1)%n+1 , b b b数组指向下标为 ( i − 1 ) % m + 1 (i-1) \% m+1 (i1)%m+1

若两个数不同,则计数,当计数到达 k k k 时,求当前的时刻。

题解:

二分时刻,求出不同的数量,怎么求呢?

因为数组中的数两两不同,假设数 x x x a a a 中的位置为 p o s 1 pos1 pos1,在 b b b中的位置为 p o s 2 pos2 pos2那么我们就要求一个最小的时刻 t t t ,满足

{ ( t − 1 ) ≡ ( p o s 1 − 1 ) ( m o d    n ) ( t − 1 ) ≡ ( p o s 2 − 1 ) ( m o d    m ) \left\{ \begin{aligned} (t-1) \equiv (pos1-1) (\mod n) \\ (t -1)\equiv (pos2-1) (\mod m) \\ \end{aligned} \right. { (t1)(pos11)(modn)(t1)(pos21)(modm)

解这个式子就是中国剩余定理,但 n , m n,m nm不互质,所以要用扩展中国剩余定理即可。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e6+5;
const int N=1e5+10;
int n,m;
int p1[MAXN],p2[MAXN];
ll dp[MAXN];
ll gcd(ll a,ll b) {
    
    
    return b == 0 ? a : gcd(b,a%b);
}
ll exgcd(ll a,ll b,ll &x,ll &y) {
    
    
    if(b == 0) {
    
    
        x = 1,y = 0;
        return a;
    }
    else {
    
    
        ll res = exgcd(b,a%b,x,y);
        ll t = x;
        x = y;
        y = t - a / b * y;
        return res;
    }
}
ll excrt(ll m1,ll m2,ll a1,ll a2) {
    
    
    ll x,y,c,g;
    c = a2 - a1;
    g = exgcd(m1,m2,x,y);
    x = x * c / g;
    y = m2 / g;
    x = (x % y + y) % y;
    a1 = a1 + x * m1;
    m1 = m1 * m2 / g;
    return a1;
}
bool check(ll mid,ll k,ll lc){
    
    
    ll res=0;
    int maxx=max(n,m)*2;
    for(int i=1;i<=maxx;i++){
    
    
        if(!p1[i]||!p2[i]||!dp[i]) continue;
        if(dp[i]<=mid){
    
    
            res+=(mid-dp[i])/lc+1;
        }
        if(mid-res<k) return false;
    }
    return mid-res>=k;
}
int main()
{
    
    
    ll k;
    scanf("%d%d%lld",&n,&m,&k);
    for(int i=1,x;i<=n;i++){
    
    
        scanf("%d",&x);
        p1[x]=i;
    }
    for(int i=1,x;i<=m;i++){
    
    
        scanf("%d",&x);
        p2[x]=i;
    }
    int maxx=max(n,m)*2;
    int gc=gcd(n,m);
    for(int i=1;i<=maxx;i++){
    
    
        if(!p1[i]||!p2[i]) continue;
        if(abs(p1[i]-p2[i])%gc!=0) continue;
        dp[i]=excrt(n,m,p1[i],p2[i]);
    }
    ll l=k,r=1e18;
    ll lc=1ll*n*m/gc;
    ll ans;
    while(l<=r){
    
    
        ll mid=(l+r)>>1;
        if(check(mid,k,lc)){
    
    
            ans=mid;
            r=mid-1;
        }
        else{
    
    
            l=mid+1;
        }
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/weixin_45755679/article/details/114952203
今日推荐