• D. Two chandeliers CRT + 二分


    D. Two chandeliers CRT + 二分

    题目大意:

    给你两个序列,一个长度为 n,一个长度为 m,这两个序列的数都是两两互不相同的,这两个序列都是可以无限循环的,这两个序列里面的值都是小于等于 (2*max(n,m)) ,问当这两个序列长度为多少是,最少有 (k) 个位置的数是不同的。

    题解:

    很容易想到可以进行二分,二分答案,然后遍历 (2*max(n,m)) 求每一个数有多少个位置是相同的,这个可以用中国剩余定理(CRT)求解:

    [pos = x (mod \,n) ]

    [pos = y(mod\,m) ]

    求出有多少个一样的之后,然后判断此时的长度是否合适即可。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6+10;
    typedef long long ll;
    long long exgcd(long long a,long long b,long long &x,long long &y)
    {
        if(b==0){x=1;y=0;return a;}
        long long gcd=exgcd(b,a%b,x,y);
        long long tp=x;
        x=y; y=tp-a/b*y;
        return gcd;
    }
    int ai[10],bi[10];
    long long mul(long long a,long long b,long long mod)
    {
        long long res=0;
        while(b>0){
            if(b&1) res=(res+a)%mod;
            a=(a+a)%mod;
            b>>=1;
        }
        return res;
    }
    long long excrt()
    {
        long long x,y;
        long long M=bi[1],ans=ai[1];
        long long a=M,b=bi[2],c=(ai[2]-ans%b+b)%b;
        long long gcd=exgcd(a,b,x,y),bg=b/gcd;
        if(c%gcd!=0) return -1;
        x=mul(x,c/gcd,bg);
        ans+=x*M,M*=bg;
        ans=(ans%M+M)%M;
        return ans;
    }
    ll gcd(ll a,ll b){
        return b==0?a:gcd(b,a%b);
    }
    ll lcm(ll a,ll b){
        return a*b/gcd(a,b);
    }
    ll n,m,k,LCM,crt[maxn];
    int a[maxn],b[maxn];
    bool check(ll x){
        ll ans = 0;
        int len = 2*max(n,m);
        for(int i=1;i<=len;i++) {
            if (a[i] && b[i] && a[i] <= x && b[i] <= x) {
                ll v = crt[i];
                if (v != -1 && x >= v) {
                    ans += (x - v) / LCM;
                    if (v > 0) ans++;
                }
            }
            if(x-ans<k) return false;
        }
        return x - ans >= k;
    }
    int main(){
        scanf("%lld%lld%lld",&n,&m,&k);
        LCM = lcm(n,m);
        for(int i=1,x;i<=n;i++) scanf("%d",&x),a[x] = i;
        for(int i=1,x;i<=m;i++) scanf("%d",&x),b[x] = i;
        int len = 2*max(n,m);
        for(int i=1;i<=len;i++){
            if(a[i]&&b[i]){
                bi[1] = n, bi[2] = m;
                ai[1] = a[i] % n, ai[2] = b[i] % m;
                crt[i] = excrt();
            }
        }
        ll l = 1,r = 2*max(n,m)*k,ans = 0;
        while(l<=r){
            ll mid = (l+r)>>1;
            if(check(mid)) ans = mid,r = mid - 1;
            else l = mid + 1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    28.数组中出现次数超过长度一半的数字(python)
    [leetcode] 145. 二叉树的后序遍历
    [leetcode] 144. 二叉树的前序遍历
    [leetcode] 94. 二叉树的中序遍历
    [leetcode] 93. 复原IP地址
    [leetcode] 206. 反转链表
    [leetcode] 92. 反转链表 II
    [leetcode] 91. 解码方法
    [leetcode] 90. 子集 II.md
    [leetcode] 88. 合并两个有序数组
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14533067.html
Copyright © 2020-2023  润新知