中国剩余定理

来自:https://blog.csdn.net/litble/article/details/75807726
写的很强

一开始觉得这东西好难。。。后来发现好像也没有这么难。。。
我们来看一道题目:

树王种了一棵treap,她现在决定把这棵treap改造为一棵无旋多叉triep,于是她摘下了treap的所有节点,发现如果她把节点3个3个一打包,会剩下2个节点。如果她把节点5个5个一打包,会剩下3个节点,如果把节点7个7个一打包,会剩下2个节点,求这棵treap最少有多少节点?

首先假如我们求出这样三个数k1,k2,k3,满足k1与3互质且是5和7的倍数,k2与5互质且是3,7的倍数,k3与7互质且是3和5的倍数,那么容易意会得到,k1∗2+k2∗3+k3∗2一定会是一个满足题目条件的数。而题目的通解可表示为这个数每次都加上3,5,7的最小公倍数
辣么如何求出k1,k2,k3呢?

首先我们求出3,5,7的lcm=105
然后我们令:
x1=105/3=35
x2=105/5=21
x3=105/7=15
然后我们求解以下方程:
a∗x1%3=1 //a×x1是k1,a×x1%3=1,那么2×a×x1%3=2与题意相符
b∗x2%5=1
c∗x3%7=1
啊呀这个格式的式子好眼熟。。。那么就愉快地用扩展欧几里德求出来吧!
a=2,b=1,c=1。
答案就是:
ans=(a∗x1∗2+b∗x2∗3+c∗x3∗2)%lcm=23
多棒啊!可爱的代码也很好写啊~

Code:

自己敲的完整代码
#include <iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll m[15],a[15];
ll ex_gcd(ll a,ll b,ll &x,ll &y)   //扩展gcd得到的x即为特解
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }


    ll r=ex_gcd(b,a%b,x,y);
    ll t=y;
    y=x-(a/b)*y;
    x=t;
    return r;
}
ll china(int n,ll *m,ll *a)      //中国剩余定理
{
    ll lcm=1,y,x,ans=0;
    for(int i=0;i<n;i++)
        lcm*=m[i];
     for(int i=0;i<n;i++)
     {
         ll w=lcm/m[i];            
         ex_gcd(w,m[i],x,y);       //a∗x1%3=1已知x1求a
         x=(x%m[i]+m[i])%m[i];     //防止求出来的特解是负的
        ans=(ans+a[i]*x*w)%lcm;     //ans=(a∗x1∗2+b∗x2∗3+c∗x3∗2)%lcm=23
     }

    return ans;
}
int main()
{
   int n;
   cin>>n;
   for(int i=0;i<n;i++)
   {
       cin>>m[i]>>a[i];
    }
    cout<<china(n,m,a);


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值