[luogu 4777] exCRT

题目传送-Luogu4777

题目传送-POJ2891

题意:

给若干同余方程组
\[\begin{cases}x&\equiv&x_1&\pmod {p_1}\\x&\equiv&x_2&\pmod {p_2}\\ &&\vdots\\x&\equiv&x_n&\pmod {p_n}\end{cases}\]
求最小的非负整数解\(x\),如果无解输出\(-1\)

题解:

exCRT裸题,算法学习见->我的另一篇博客

过程:

luogu:部分操作需要用到快速乘
POJ:多组数据+禁止__gcd+不告诉你n=100000

代码:

只给出luogu代码

const int N=100010;
int n;
inline void exgcd(ll a,ll b,ll &x,ll &y) {if(!b) {x=1; y=0; return;} exgcd(b,a%b,y,x); y-=a/b*x;}
inline ll lcm(ll a,ll b) {return a/__gcd(a,b)*b;}
inline ll Up(ll x,ll y) {return x/y+(x%y!=0);}
inline ll Mul(ll x,ll y,ll P) {
    // printf("%lld %lld %lld\n",x,y,P);
    ll ret=0; y%=P;
    for(;y;y>>=1,x=x+x) {
        // puts("?");
        if(x>=P) x-=P;
        if(y&1) {
            ret=ret+x;
            if(ret>=P) ret-=P;
        }
    }
    return ret;
}
struct FUNCTION {
    ll k,r;
    inline void in() {
        read(k); read(r);
    }
}f[N];
bool fl=1;
inline FUNCTION Merge(FUNCTION a,FUNCTION b) {
    ll z=b.r-a.r,x1,x2,g=__gcd(a.k,b.k); exgcd(a.k,b.k,x1,x2);
    if(z%g!=0) {puts("-1"); fl=0; return;} ll tim=z/g;
    if(tim<0) {x1=-x1; tim=-tim;}
    if(x1<0) {
        ll add=b.k/g;
        x1+=add*Up(-x1,add);
        // assert(x1>=0);
    }
    // assert(x1>=0);
    FUNCTION ret;
    ret.k=lcm(a.k,b.k);
    ret.r=Mul(a.k,Mul(x1,tim,ret.k),ret.k)+a.r;
    // assert(ret.r>=0);
    return ret;
}
signed main() {
    read(n);
    for(int i=1;i<=n;i++) f[i].in();
    for(int i=2;i<=n;i++) {
        f[1]=Merge(f[1],f[i]);
        if(!fl) return 0;
    }
    printf("%lld\n",f[1].r);
    return 0;
}

用时:30min

转载于:https://www.cnblogs.com/functionendless/p/9445650.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值