zoukankan      html  css  js  c++  java
  • poj2891

    /*
    
        题目大意:对于m%a1=r1,m%a2=r2...m%ak=rk,求最小的非负的m的值
    
        联立前面两个方程组则有a1*x-a2*y=r2-r1;
        可利用欧几里得算法求出最小的非负x  那么满足前两个方程的一个特解m=a1*x+r1;
        所有解M=m+x*LCD(a1,a2);---LCD(a1,a2)最小公倍数
        在联立第3个方程,另a1 = LCD(a1,a2),a2 = a3,r2=r3;
        那么有方程 a1*x-a2*y=r2-m,继续利用欧几里得算出x,得到新的m即可
    */
    
    
    #include <iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    __int64 m,t,n,a1,r1,a2,r2,ans,d;
    bool flag;
    __int64 extend_euclid(__int64 a,__int64 b,__int64 &x,__int64 &y)
    {
          //b等于0时递归结束,得到该步的解,通过该解返回到上一步的出上一步的解
        if(b==0)
         {
             x=1;
             y=0;
             return a;
         }
         __int64 d = extend_euclid(b,a%b,x,y);
         __int64 t = x;
         x=y;
         y=t-a/b*y;
         return d;//a,b的最大公约数
    }
    void fun(__int64 a,__int64 b,__int64 c)
    {
        d = extend_euclid(a,b,ans,t);//最大公约数
        if(c%d!=0)
            flag=false;
        ans=ans*c/d;
        __int64 r = fabs(b/d);
        ans = (ans%r+r)%r;//得到最小非负整数解
        m=m+ans*a1;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%I64d",&n)!=EOF)
        {
            flag = true;
            ans= 0;
            scanf("%I64d%I64d",&a1,&r1);
            m=r1;
            for(int i=1;i<n;i++)
            {
                scanf("%I64d%I64d",&a2,&r2);
                fun(a1,-a2,r2-m);
                a1=fabs(a1*a2/d);//保证最小公倍数为正数
            }
            if(!flag)
                printf("-1
    ");
            else
                printf("%I64d
    ",m);
        }
    
        return 0;
    }
  • 相关阅读:
    JAVA整理05---手写简单的linkedlist来学习linkedlist
    JAVA整理04---手写简单的arraylist来学习arraylist
    java整理03--常用类
    java整理02--面向对象深入
    每周学习进度
    软件工程课程总结
    梦断代码阅读笔记03
    scrum第二阶段项目冲刺_day10
    scrum第二阶段项目冲刺_day09
    scrum第二阶段项目冲刺_day08
  • 原文地址:https://www.cnblogs.com/wt20/p/5768841.html
Copyright © 2011-2022 走看看