• Codeforces 1500B/1501D


    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)

    可以得到以下两式:

    [left { egin{aligned} p\%n&=i\ p\%m&=j end{aligned} ight . ]

    套扩展中国剩余定理即可(由于二分对下标不影响,故这部分需预处理)


    其后每次二分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;
    }
    

    https://blog.csdn.net/qq_36394234/article/details/115185159

  • 相关阅读:
    MySQL数据库之索引
    python面向对象编程
    linux端口占用
    lintcode
    java基础
    lintcode
    linux 常用命令
    Docker & Kubernates
    angular preparation
    java 命令行
  • 原文地址:https://www.cnblogs.com/stelayuri/p/14580145.html
Copyright © 2020-2023  润新知