• 牛客多校第十场 D Han Xin and His Troops 中国剩余定理


    题意:

    韩信有若干个兵,给定你若干个模数和余数,再给你一个1e18以内的范围限制,求解同余方程组,如果无解,输出“他一定在撒谎”,如果最小解超出范围限制,输出“他可能在撒谎”,否则输出最小解

    注意:不保证模数互质,也不保证“他可能在撒谎”的情况答案不爆long long

    题解:

    因为不保证模数互质,需要用excrt求解。

    假算法:把excrt的板子翻译成python,然后一脸自闭地调程序

    n=0
    m=0
    bi=[]
    ai=[]
    
    def ggcd(_m,_n):
        if _n == 0:
            _x = 1
            _y = 0
            return _m,_x
        _a1 = _b = 1
        _a = _b1 = 0
        _c = _m
        _d = _n
        _q = int(_c//_d)
        _r = _c%_d
        while _r:
            _c = _d
            _d = _r
            _t = _a1
            _a1 = _a
            _a = _t-_q*_a
            _t = _b1
            _b1 = _b
            _b = _t-_q*_b
            _q = int(_c//_d)
            _r = _c%_d
        _x = _a
        _y = _b
        return _d,_x
        
    def excrt():
        x=0
        y=0
        k=0
        gcd=0
        M=bi[1]
        ans=ai[1]
        #print(ai[1],bi[1])
        i=2
        while(i<=n):
            
            a=M
            b=bi[i]
            c=(ai[i]-ans%b+b)%b
            
            gcd,x=ggcd(a,b)
            bg=b//gcd
            
            if(c%gcd!=0):
                return -1
            x=(x*c//gcd)%bg
            ans=ans+(x*M)
            M=M*bg
            ans=(ans+M)%M
            #print(M,ans,a,b,c,gcd,bg,x)
            i=i+1
        return (ans%M+M)%M
    #xx=0
    #yy=0
    #print(exgcd(3,6,xx,yy))
    n,m = map(int,input().split())
    i=1
    ai.append(0)
    bi.append(0)
    while(i<=n):
        u,v=map(int,input().split())
        bi.append(u)
        ai.append(v)
        i=i+1
    anss=excrt()
    if(anss<0):
        print("he was definitely lying")
    elif(anss>m):
        print("he was probably lying")
    else:
        print(anss)
    #不要吐槽我的空格tab混用了

    正解:先暴力枚举,计算两两模数的gcd,判断同余方程组是否有解,在保证有解的情况下,将excrt中的模乘过程改成暴力加(龟龟速乘?),一旦超出范围立刻停止运算。

    此方法仅适用于同余方程数量和数值都较小的情况。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll ans,n,a[105],p[105],base,M;
    
    const char *definitely_lie = "he was definitely lying";
    const char *probably_lie = "he was probably lying";
    
    int main(){
        cin >> n >> M;
        for (int i=0;i<n;i++) cin >> p[i] >> a[i];
        for (int i=0;i<n;i++)
        for (int j=i+1;j<n;j++){
            ll d=__gcd(p[i],p[j]);
            if (d!=1){
                if (a[i]%d!=a[j]%d){
                    puts(definitely_lie);
                    return 0;
                }
            }
        }
        ans=0; base=1;
        for (int i=0;i<n;i++){
            while (ans%p[i]!=a[i]) {
                ans+=base;
                if (ans>M){
                    puts(probably_lie);
                    return 0;
                }
            }
            ll gg=p[i]/__gcd(base,p[i]);
            if (M/base>=gg) base*=gg;
            else {
                for (int j=i+1;j<n;j++) if (ans%p[j]!=a[j]){
                    puts(probably_lie);
                    return 0;
                }
                printf("%lld
    ",ans);
                return 0;
            }
        }
        for (int i=0; i<n; i++) assert(ans % p[i] == a[i]);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    如何把新加的分区挂载到指定目录下
    怎样通过U盘安装启动Centos6.8
    Redis 单机安装【一】
    Linux漏洞扫描工具【lynis】
    mysql 主从 重新同步
    Centos 6.8下安装oracle10g数据库、
    监控服务supervisor服务的安装及使用
    制作c#桌面应用程序 安装程序 卸载程序
    Microsoft Visual SourceSafe 2005 服务端安装配置过程以及出现的问题,以及解决方法!
    .NET中的CSV导入导出
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11371739.html
Copyright © 2020-2023  润新知