zoukankan      html  css  js  c++  java
  • extend_gcd求解不定方程/膜线性方程/乘法(模)逆元

    形如a*x+b*y=c

    为不定方程,a,b>0其实无所谓,因为gcd(a,b)=gcd(|a|,|b|)   //gcd为最大公约数

    由数论的定理所知,当c%gcd==0,不定方程有解,现在我们来求这个解.

    gcd=gcd(a,b);a*b=gcd*lcm;  //lcm为最小公倍数

    a'=a/gcd;b'=b/gcd;c'=c/gcd; a'目前与b'互质  

    令c''=1=a'*x+b'*y;

    利用extend_gcd求出一组特解。(x0,y0)

    (x0*c'.y0*c')为 a'*x+b'*y=c'的一组特解

    由方程解的思想求出其通解;x=x0*c'+b'*t;    y=y0*c'-a'*t;再用通解去求解题目

    今天花了一晚上时间纠结了一个显而易见的问题。果然当局者迷。

    我现在就想大笑一场。哈哈哈哈哈哈哈哈

    UVA,10413

    题目意思:t个case,n个野人,C,P,L分别代表初始洞穴,隔天移动洞穴数,存活天数。

    问:最小的洞穴数,使得在n个野人在各自存活期不遇见。

    数据:1*10^6 可以接受,所以此题以初值为野人中初始洞穴最大数,枚举就可以过了。

    源代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 int x,y,gcd,n;
     8 int C[20],P[20],L[20];
     9 
    10 void extend_gcd(int a,int b)
    11 {
    12     if(b==0)
    13     {
    14         x=1;
    15         y=0;
    16         gcd=a;
    17         return;
    18     }
    19     extend_gcd(b,a%b);
    20     int tmp=x;
    21     x=y;
    22     y=tmp-a/b*y;
    23     return;
    24 }
    25 
    26 bool solve(int i,int j,int m)
    27 {
    28     int c=C[i]-C[j];
    29     int b=m;
    30     int a=P[j]-P[i];
    31     extend_gcd(a,b);
    32     if(c%gcd) return false;
    33     x*=c/gcd;
    34     if(gcd<0) gcd=-gcd;
    35 //因为x=x+b/gcd*k,所以x中包含了若干个b/gcd的代数和差
    36 //因此用x对b/gcd取模,注意负数得x的最小正值
    37     x=(x%(b/gcd)+b/gcd)%(b/gcd);
    38     if(x<=L[i] && x<=L[j])
    39         return true;
    40     return false;
    41 }
    42 bool test(int m)
    43 {
    44     for(int i=0;i<n-1;i++)
    45         for(int j=i+1;j<n;j++)
    46         {
    47             if(solve(i,j,m)) return false;
    48         }
    49     return true;
    50 }
    51 
    52 
    53 int main()
    54 {
    55     int t;
    56     scanf("%d",&t);
    57     while(t--)
    58     {
    59         scanf("%d",&n);
    60         int lb=0;
    61         for(int i=0;i<n;i++)
    62         {
    63             scanf("%d %d %d",C+i,P+i,L+i);
    64             lb=max(lb,C[i]);
    65             C[i]--;
    66         }
    67         while(lb<=1000000)
    68         {
    69             if(test(lb)) break;
    70             lb++;
    71         }
    72         printf("%d
    ",lb);
    73     }
    74     return 0;
    75 }
    76 //提供测试数据
    77 Sample Input
    78 2
    79 3
    80 1 3 4
    81 2 7 3
    82 3 2 1
    83 5
    84 1 2 14
    85 4 4 6
    86 8 5 9
    87 11 8 13
    88 16 9 10
    89 Sample Output
    90 6
    91 33

    补充膜逆元//

    a≡a^-1(mod n) 表示a同余n于a^-1    变式子:a*a^-1≡1(mod n)  即a^-1为a的膜逆元   有解的充分必要条件为a与n互质

    若膜逆元存在,可以转换为a*b≡1(mod n)利用extend_gcd求不定方程的解来得到乘法逆元的通解。

    a*b+n*y=1  extend_gcd(a,n)  解出一个b(mod n)取其最小值(正负特别考虑)

    一般的:a*b+n*y=g   a与n互质,g!=0则无解

    因为:(a*b+n*y)(mod n)=g(mod n)  a*b(mod n)=g(mod n)(g<n)  g mod n !=1

    则a*b!=1即b不是a的模逆元

    欧拉定理中的模逆元    

    a与n为两个互质的正整数,a^f(n)≡1(mod n) f(n)为小于n且与n互质的正整数个数

    a^f(n)=a*a^(f(n)-1)≡1(mod n)即a^(f(n)-1)为a的模n之逆元

     中国剩余定理

    x≡a1(mod m1)

    x≡a2(mod m2)

    ...

    x≡ai(mod mi)

    m1,m2....mi互质,则对任意的a1,a2...ai方程组有解

    且通解为:x=a1*t1*M1+a2*t2*M2+....+ai*ti*Mi+k*M (Mi=M/mi,  M=m1*m2*...*mi)

    具体证明及例子参考wiki

    uva 11754

     

    大致题意:

    给你两个元素C,S  C为行数,也代表互质元的个数,S代表要输入的最小的S个解。

    接着的X,k为质数元,k代表要求的n对X取余之后的存在的余数个数,(这里n不唯一,所以对X有多个余数,

    申明:一个数n对另一个数m取余数有且仅有一个

    具体想法:由于k为(1,100)当有C=9个k的时候dfs去搜的话会爆掉。

    所以用特殊枚举法,当total=k[0]*k[1]*....*k[i]<10000的时候用dfs去搜

    否则 找到一个基元s 用t*X[s]+Y[s][j]去枚举。  //这里s为当k/x最小的时候所取的值

    //因为k越小,x越大,代表余数个数越小,除数越大,所以枚举所需要的次数越少。

    //详细解释-重点:  n=t*X[s]+Y[s][j] (t=0,1.....,)(j=0,1....k[s])因为n%X[s]=Y[s][j]。

    //即无论要求多少个n,都能够从一个X[s]和其余数得出来。所以选择需要枚举次数最小的那一组(X[s],Y[s][j])(j=0,1...k[s])速度最快。

    源代码://写了一下午,终于干掉了,进步了不少,继续加油!

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <set>
      6 #include <vector>
      7 
      8 using namespace std;
      9 
     10 typedef long long ll;
     11 const int maxc=15;
     12 const int maxs=105;
     13 const int limit=10000;
     14 
     15 ll total;
     16 int C,S,bestc;
     17 int X[maxc],k[maxc],Y[maxc][maxs];
     18 
     19 void init()
     20 {
     21     total=1;
     22     bestc=0;
     23     for(int i=0;i<C;i++)
     24     {
     25         scanf("%d %d",&X[i],&k[i]);
     26         total*=k[i];
     27         for(int j=0;j<k[i];j++)
     28             scanf("%d",&Y[i][j]);
     29         sort(Y[i],Y[i]+k[i]);
     30         if(X[bestc]*k[i]<X[i]*k[bestc])
     31             bestc=i;
     32     }
     33 }
     34 
     35 set<int> vis[maxc];
     36 void solveEnum(int s)
     37 {
     38     for(int i=0;i<C;i++)
     39     {
     40         if(i==s)
     41             continue;
     42         vis[i].clear();
     43         for(int j=0;j<k[i];j++)
     44             vis[i].insert(Y[i][j]);
     45     }
     46     for(int t=0;S;t++)
     47     {
     48         for(int i=0;i<k[s];i++)
     49         {
     50             ll n=(ll)X[s]*t+Y[s][i];
     51             if(n==0)
     52                 continue;
     53             bool flag=true;
     54             for(int j=0;j<C;j++)
     55             {
     56                 if(j==s)
     57                     continue;
     58                 if(!vis[j].count(n%X[j]))
     59                 {
     60                     flag=false;
     61                     break;
     62                 }
     63             }
     64             if(flag)
     65             {
     66                 printf("%lld
    ",n);
     67                 if(--S==0)
     68                     break;
     69             }
     70         }
     71     }
     72 }
     73 
     74 void extend_gcd(ll a,ll b,ll& d,ll& x,ll& y)
     75 {
     76     if(!b)
     77     {
     78         x=1;
     79         y=0;
     80         d=a;
     81         return;
     82     }
     83     extend_gcd(b,a%b,d,y,x);
     84     y-=a/b*x;
     85     return;
     86 }
     87 
     88 vector<int> sol;
     89 int a[maxc];
     90 int China(int n,int* s,int* m)
     91 {
     92     ll M=1,d,y,x=0;
     93     for(int i=0;i<n;i++)
     94         M*=m[i];
     95     for(int j=0;j<n;j++)
     96     {
     97         ll w=M/m[j];
     98         extend_gcd(m[j],w,d,d,y);
     99         x=(x+y*w*a[j])%M;
    100     }
    101     return (x+M)%M;
    102 }
    103 
    104 void dfs(int dep)
    105 {
    106     if(dep==C)
    107         sol.push_back(China(C,a,X));
    108     else
    109     {
    110         for(int i=0;i<k[dep];i++)
    111         {
    112             a[dep]=Y[dep][i];
    113             dfs(dep+1);
    114         }
    115     }
    116 }
    117 
    118 void solveChina()
    119 {
    120     sol.clear();
    121     dfs(0);
    122     sort(sol.begin(),sol.end());
    123     ll M=1;
    124     for(int i=0;i<C;i++)
    125         M*=X[i];
    126     for(int t=0;S;t++)
    127     {
    128         for(int j=0;j<sol.size();j++)
    129         {
    130             ll n = M*t+sol[j];
    131             if(n>0)
    132             {  printf("%lld
    ",n);
    133                 if(--S==0)
    134                     break;
    135             }
    136         }
    137     }
    138 }
    139 int main()
    140 {
    141     while(scanf("%d %d",&C,&S) == 2 && C+S)
    142     {
    143         init();
    144         if(total>limit)
    145             solveEnum(bestc);
    146         else
    147             solveChina();
    148         puts("
    ");
    149     }
    150     return 0;
    151 }
    活在现实,做在梦里。
  • 相关阅读:
    HashMap遍历的两种方式
    抽象类和接口的区别是什么
    “用户、组或角色'XXX'在当前数据库中已存在”问题
    FCKEditor在IE10下的不兼容问题解决方法
    ADODB.Connection 错误 '800a0e7a' 未找到提供程序。该程序可能未正确安装。解决方法!
    ASP.NET中Url重写后,打不开真正的Html页面
    运用正则表达式在Asp中过滤Html标签代码的四种不同方法
    静态页分页功能js代码
    .NET生成静态页面的方案总结
    禁止ViewState的3种解决方法
  • 原文地址:https://www.cnblogs.com/do-it-best/p/5335172.html
Copyright © 2011-2022 走看看