日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

刘汝佳训练指南——数论专题知识点总结:

發布時間:2023/11/30 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 刘汝佳训练指南——数论专题知识点总结: 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數論是一個神奇的東西,各種結論都很經典,有些懂,有些自己還不是很懂。

接下來就一個一個的介紹吧。

第一、素數,素數本身就是一個很讓人驚奇的數,因為它代表的是唯一,自己就有連個因數,一個是1,一個是自己,因為1是每個數都具備的因子(除了0),所以,它也就相當于只有自己。是一個自我感覺很良好的人呀!

最樸素的算法當然是從2-sqrt(2)里面找因子,如果沒有,就說明它是個素數。為什么到sqrt(n)?你想,sqrt(n)* sqrt(n)= n,而你因子的個數怎么算?是不是從1-sqrt(n)里面的因子數 * 2?顯然可得,因子數是關于sqrt(n)對稱的,這邊有幾個那邊就有幾個,所以枚舉一般就行!

高深一點,有miller-robin,前面寫過這個算法,但是好像不經常用,也就沒去看過了。但是有一個是比較經常用的,那就是篩法欲求范圍素數。這個思想運用廣泛,euler函數里面也用到了這個思想。

貼出篩素數的算法,一會加上miller-robin:

[cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<math.h>??
  • #include?<iostream>??
  • #include?<string>??
  • ??
  • using?namespace?std;??
  • ??
  • const?int?MAXN?=?1000000?+?11;??
  • ??
  • bool?p[MAXN];??
  • ??
  • int?index[MAXN];??
  • ??
  • void?init()??
  • {??
  • ????memset(p,?0,?sizeof(p));??
  • ????p[0]?=?1;??
  • ????p[1]?=?1;??
  • ????for?(int?i?=?4;?i?<?MAXN;?i?+=?2)??
  • ????{??
  • ????????p[i]?=?1;??
  • ????}??
  • ????int?cnt?=?0;??
  • ????index[cnt++]?=?2;???
  • ????for?(int?i?=?3;?i?<?(int)sqrt(MAXN?*?1.0);?i?+=?2)??
  • ????{??
  • ????????if?(!p[i])??
  • ????????{??
  • ????????????index[cnt++]?=?i;??
  • ????????????int?k?=?i?*?2;??
  • ????????????for?(int?j?=?k;?j?<?MAXN;?j?+=?i)??
  • ????????????{??
  • ????????????????p[j]?=?1;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ????/*?
  • ????for?(int?i?=?0;?i?<?cnt;?i++)?
  • ????{?
  • ????????printf("%d\n",?index[i]);?
  • ????}?
  • ????*/??
  • }??
  • ??
  • void?sieve()//這是另外一種,這種看上去簡單,但是和上面的思想是一摸一樣的.???
  • {??
  • ????int?m?=?(int)sqrt(n?+?0.5);??
  • ????for?(int?i?=?2;?i?<?m;?i++)??
  • ????{??
  • ????????if?(!p[i])??
  • ????????{??
  • ????????????for?(int?j?=?i?*?i;?j?<?n;?j?+=?i)??
  • ????????????{??
  • ????????????????p[j]?=?1;??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • ??
  • int?main()??
  • {??
  • ????init();??
  • ????sieve();??
  • ????system("pause");??
  • ????return?0;??
  • }??

  • 二、歐幾里德算法。歐幾里德算法的精髓思想大概是輾轉相除吧。還是比較好理解的,難點的就是擴展歐幾里德算法,求a*x + b*y = gcd(a,b);這是一個解線性方程組的最佳算法。還有一個很好的應用就是求乘法逆元,這個應用很大,因為有很多時候因為數據量非常大,都會modulo一個素數。而逆元可以把除以一個數變成乘法,這個就比較好了。

    貼出這些算法:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<iostream>??
  • #include?<string>??
  • ??
  • using?namespace?std;??
  • ??
  • typedef?long?long?LL;??
  • ??
  • void?extgcd(LL?a,?LL?b,?LL?&d,?LL?&x,?LL?&y)??
  • {??
  • ????if?(b?==?0)??
  • ????{??
  • ????????x?=?1;??
  • ????????y?=?0;??
  • ????????d?=?a;??
  • ????}??
  • ????else??
  • ????{??
  • ????????extgcd(b,?a?%?b,?d,?y,?x);??
  • ????????y?-=?x?*?(a?/?b);??
  • ????}??
  • ??????????
  • }??
  • ??
  • LL?inv(LL?a,?LL?n)??
  • {??
  • ????LL?d,?x,?y;??
  • ????extgcd(a,?n,?d,?x,?y);??
  • ????return?d?==?1???(x?+?n)?%?n?:?-1;??
  • }??
  • ??
  • int?main()??
  • {??
  • ????int?ans?=?inv(2,?5);??
  • ????cout?<<?ans?<<?endl;??
  • ????system("pause");??
  • ????return?0;??
  • }??

  • 三、歐拉函數phi(n)。首先就要弄明白歐拉函數求得的含義:1-n之間和n互素的數的個數。公式是

    phi(n) = n * (1 - 1 / p1) (1 - 1 / p2) (1- 1 / p3) (1 - 1 / p4)……

    p1,p2,p3都是n素因數分解的素因數。有了這個公式就好辦了。

    現在貼出素因數分解的代碼,其實在euler_phi函數里面就包含了這個思想,就是含有這個因子就把這個因子除盡。

    素因數分解:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<math.h>??
  • #include?<iostream>??
  • #include?<string>??
  • ??
  • using?namespace?std;??
  • ??
  • int?main()??
  • {??
  • ????int?N;??
  • ????while?(scanf("%d",?&N)?!=?EOF)??
  • ????{??
  • ????????int?cnt?=?0;??
  • ????????cout?<<?"N?=?";??
  • ????????for?(int?i?=?2;?i?<=?(int)sqrt(N?+?0.5);?i++)??
  • ????????{??
  • ????????????if?(N?%?i?==?0)??
  • ????????????{??
  • ????????????????cout?<<?i?<<?"^";??
  • ????????????????while?(N?%?i?==?0)??
  • ????????????????{??
  • ????????????????????N?/=?i;??
  • ????????????????????cnt++;??
  • ????????????????}???
  • ????????????????cout?<<?cnt?<<?"?";??
  • ????????????}??
  • ????????}??
  • ????????if?(N?>?1)??
  • ????????{??
  • ????????????cout?<<?N?<<?"^1";??
  • ????????}??
  • ????????cout?<<?endl;??
  • ????}??
  • ????system("pause");??
  • ????return?0;??
  • }???
  • 接下來是euler_phi:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<math.h>??
  • #include?<iostream>??
  • #include?<string>??
  • /*?
  • ?*首先你得清楚,歐拉函數的公式是什么:?
  • ?*推導出來的最簡潔的公式是:phi(n)?=?n(1?-?1/p1)(1?-?1/p2)……?
  • ?*這就可以輕松的求出來了??
  • ?*phi(n)?表示的含義是,不超過x且和x互素的整數個數.??
  • */??
  • ??
  • using?namespace?std;??
  • ??
  • typedef?long?long?LL;??
  • ??
  • const?int?MAXN?=?100000?+?11;??
  • ??
  • int?phi[MAXN];??
  • ??
  • int?euler_phi(int?n)??
  • {??
  • ????LL?ans?=?n;??
  • ????for?(int?i?=?2;?i?<=?(int)sqrt(n?+?0.5);?i++)??
  • ????{??
  • ????????if?(n?%?i?==?0)??
  • ????????{??
  • ????????????ans?=?ans?/?i?*?(i?-?1);??
  • ????????????while?(n?%?i?==?0)??
  • ????????????{??
  • ????????????????n?/=?i;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ????if?(n?>?1)??
  • ????{??
  • ????????ans?=?ans?/?n?*?(n?-?1);??
  • ????}??
  • ????return?ans;??
  • }??
  • ??
  • void?phi_table(int?n)??
  • {??
  • ????memset(phi,?0,?sizeof(phi));??
  • ????phi[1]?=?1;??
  • ????for?(int?i?=?2;?i?<=?n;?i++)?//因為要將所有的phi都求出來,所以要循環到n,因為有一些大于sqrt(n)???
  • ????{????????????????????????????//的素數還沒有求出結果;???
  • ????????if?(!phi[i])??
  • ????????{??
  • ????????????for?(int?j?=?i;?j?<?n;?j?+=?i)??
  • ????????????{??
  • ????????????????if?(!phi[j])??
  • ????????????????{??
  • ????????????????????phi[j]?=?j;??
  • ????????????????}??
  • ????????????????phi[j]?=?phi[j]?/?i?*?(i?-?1);??
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • ??
  • void?print(int?n)??
  • {??
  • ????for?(int?i?=?1;?i?<=?n;?i++)??
  • ????{??
  • ????????printf("phi[%d]?=?%d\n",?i,?phi[i]);??
  • ????}??
  • }???
  • ??
  • int?main()??
  • {??
  • //??cout?<<?"phi(i)?=?"?<<?euler_phi(3)?<<?endl;??
  • ????phi_table(30);??
  • ????print(30);??
  • ????system("pause");??
  • ????return?0;??
  • }??
  • 這只是最基本的算法,當然數論里面還有很多種算法,我會后續加上來的。


    四、中國剩余定理。解決多個模方程,但是變量還是一個的問題,即x = a[i] (% m[i])。方法是令M為所有的m[i]的乘積,wi = M / mi,則gcd(wi, mi) = 1.使得wi * p + mi * q = 1,可以用extgcd求出來對于wi的p解,令e = ?wi * pi,則方程組等價于方程x = e1*a1 + e2*a2 + e3*a3…… 且注意x是唯一解。

    代碼如下:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<iostream>??
  • #include?<string>??
  • /*?
  • ?*中國剩余定理用與解決?x?=?a[i]?(%?m[i]);?
  • ?*而m[i]又每每互素,將會求的唯一的最小解。??
  • ?*/???
  • ??
  • using?namespace?std;??
  • ??
  • typedef?long?long?LL;??
  • ??
  • const?int?MOD?=?1000000000?+?7;??
  • ??
  • void?extgcd(int?a,?int?b,?int?&d,?int?&x,?int?&y)??
  • {??
  • ????if?(b?==?0)??
  • ????{??
  • ????????d?=?a;??
  • ????????x?=?1;??
  • ????????y?=?0;??
  • ????}??
  • ????else??
  • ????{??
  • ????????extgcd(b,?a?%?b,?d,?y,?x);??
  • ????????y?-=?x?*?(a/?b);??
  • ????}??
  • }??
  • ??
  • int?china(int?n,?int?*a,?int?*m)??
  • {??
  • ????int?M?=?0;??
  • ????int?x,?y,?d;??
  • ????int?ans?=?0;??
  • ????for?(int?i?=?0;?i?<?n;?i++)??
  • ????{??
  • ????????M?+=?m[i];??
  • ????}??
  • ????for?(int?i?=?0;?i?<?n;?i++)??
  • ????{??
  • ????????int?w?=?M?/?m[i];??
  • ????????extgcd(m[i],?w,?d,?x,?y);??
  • ????????ans?=?((LL)ans?+?(LL)y?*?w?*?a[i])?%?MOD;??
  • ????}??
  • ????return?(ans?+?MOD)?%?MOD;??
  • }??
  • ??
  • int?main()??
  • {??
  • ????system("pause");??
  • ????return?0;??
  • } ?
  • 總結

    以上是生活随笔為你收集整理的刘汝佳训练指南——数论专题知识点总结:的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。