zoukankan      html  css  js  c++  java
  • 【lydsy1407】拓展欧几里得求解不定方程+同余方程

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1407

    题意:

    有n个野人,野人各自住在第c[i]个山洞中(山洞成环状),每年向前走p[i]个山洞,到这个山洞住下来。

    每个野人的寿命为l[i],问至少需要多少个山洞,才能让野人在有生之年永远不住在同一个山洞。

    题解:

    原本不会拓展欧几里得和同余方程,在这里尽量详细地写一下由这题学到的东西。

    我原本是从网上看各类题解然后打的,因为不理解和某些题解上的错误,导致调了很久。

    下面写我的题解,如有错误,敬请指出。

    设山洞的数量为m。

    首先,对于n=2时,若相遇,则得同余方程 c[i]+x*p[i] = c[j]+x*p[j] (mod m)

    移项,得:(p[i]-p[j])*x=c[j]-c[i] (mod m)

    即:(p[i]-p[j])*x + m*y = c[j]-c[i]

    则由于p[i]-p[j]、m、c[j]-c[i]已知,该方程相当于 a*x+b*y=c,可用拓展欧几里得求解。

    若该方程无解,或x小于l[i]且x小于l[j](注意是并且的关系,因为一个死了一个活着也是不能相遇的),则不会相遇。

    所以,由于n<=15,可以从max(c[i])开始枚举m(因为开始时野人都不在同一个山洞,max(c[i])一定大于等于n),两两匹配,若都不能相遇,则当前的m值为最小整数解。

    相关: 用拓展欧几里德算法求不定方程 a*x + b*y = c:

    推荐一篇很好的博文:http://www.cnblogs.com/Rinyo/archive/2012/11/25/2787419.html

    如果c不是gcd(a,b)的倍数,则该方程无解。

    证明:

    设g=gcd(a,b),则a=a'g,b=b'g

    ax+by=c可化为g(a'x+b'y)=c

    由于g、(a'x+b'y)、c都是整数,所以c必然是g的倍数。

    拓展欧几里得:

    int exgcd(int a,int b)
    {
        if (b == 0) { x=1,y=0; return a; }
        int t = exgcd (b,a%b,x,y);
        int x0 = x , y0 = y;
        x = y0; y = x0-(a/b)*y0;
        return t;
    }

    证明:

    ax + by = gcd(a,b)

    bx'+(a%b)y'=gcd(b,a%b)

    因为gcd(a,b) = gcd(b,a%b)

    所以ax+by = bx'+(a%b)y'

    代入a%b =  a - ⌊a/b⌋*b (⌊⌋是向下取整符号)

    ax + by = bx' + (a - ⌊a/b⌋*b)y'

    ax + by = ay' + b(x'-⌊a/b⌋y')

    所以: x = y'  y = x'-⌊a/b⌋*y'

    回溯即可得出答案。

    此处求出的x和y是一组可行解,可以利用通式 

    x = x' + k*b

    y = y'  - k*a

    求出最小整数解。

    注意:ax + by = c 求的是c是gcd(a,b)的倍数时的解。

    方法一:

              方程两边同时除以g

              a'=a/g   b'=b/g   c'=c/g

              得a'x+b'y=c' 

              用拓展欧几里德算法求解a'x'+b'y'=1

              则 x = x'*c'  y = y'*c'

              这时,在用通式求最小整数解时加减的应是b'

    方法二:

              我们可以直接求出ax’ + by’ =gcd(a,b)

              则 x = x'*c/g   y = y' * c/g

              这时应注意,在求通式求最小整数解加减的仍应是b/g。(注意!)

    代码如下:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 
     7 const int N=20,M=1000010;
     8 int n;
     9 int cc[N],p[N],l[N];
    10 
    11 int maxx(int x,int y) {return x>y ? x:y;}
    12 int minn(int x,int y) {return x<y ? x:y;}
    13 int myabs(int x) {return x>0 ? x:-x;}
    14 
    15 int gcd(int a,int b)
    16 {
    17     if(b==0) return a;
    18     return gcd(b,a%b);
    19 }
    20 
    21 void exgcd(int a,int b,int &x,int &y)
    22 {
    23     if(b==0) {x=1,y=0;return ;}
    24     exgcd(b,a%b,x,y);
    25     int x0=x,y0=y;
    26     x=y0;y=x0-(a/b)*y0;
    27     return ;
    28 }
    29 
    30 bool check(int m)
    31 {
    32     for(int i=1;i<=n-1;i++)
    33         for(int j=i+1;j<=n;j++)
    34         {
    35             int a=p[i]-p[j];
    36             int b=m;
    37             int c=cc[j]-cc[i];
    38             
    39             int g=gcd(a,b);
    40             if(c%g) continue;
    41             a/=g;b/=g;c/=g;//b在此处可能变为负
    42             int x,y;
    43             exgcd(a,b,x,y);
    44             x=x*c;y=y*c;
    45             while(x>0) x-=myabs(b);
    46             while(x<=0) x+=myabs(b);
    47             if(x<=minn(l[i],l[j])) return 0;//
    48         }
    49     return 1;
    50 }
    51 
    52 int main()
    53 {
    54     scanf("%d",&n);
    55     int mx=n;
    56     for(int i=1;i<=n;i++)
    57     {
    58         scanf("%d%d%d",&cc[i],&p[i],&l[i]);    
    59         mx=maxx(mx,cc[i]);        
    60     }
    61     for(int i=mx;i<=M;i++)
    62     {
    63         if(check(i)) {printf("%d
    ",i);break;}
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    日期格式不合法
    DataGridView的Scrollbar通過編程不能自動下滾
    Sourcesafe shadown backup
    共享目錄突然不工作 
    VS2005編譯后版本如何控制
    WebBrowser用作RichTextBox
    怎樣設定MS Reporting自動橫向列印
    VSS 2005不需登錄,直接開啟的方法
    subreport cannot be shown
    An Algorithm Summary of Programming Collective Intelligence (5)
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/4763923.html
Copyright © 2011-2022 走看看