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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

P6091-[模板]原根

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P6091-[模板]原根 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P6091


題目大意

給出一個數ppp,求出它的所有在[0,p][0,p][0,p]的原根。


解題思路

原根的定義,δp(a)\delta_p(a)δp?(a)表示一個最小的nnn使得an≡1(modp)a^n\equiv1(mod\ p)an1(mod?p),若gcd(a,p)=1gcd(a,p)=1gcd(a,p)=1δp(a)=φ(p)\delta_p(a)=\varphi(p)δp?(a)=φ(p)aaappp的一個原根。

兩個個結論就是一個數有原根當且僅當它為2,4,pa,2pa2,4,p^a,2p^a2,4,pa,2pa(其中ppp為奇質數,a∈N+a\in N^+aN+)。還有若ggg表示最小正原根,那么其他原根可以被表示為gk%p(gcd(φ(p),k)=1)g^k\% p(\ gcd(\varphi(p),k)=1\ )gk%p(?gcd(φ(p),k)=1?)

這兩個結論在洛谷題解都有詳細證明,這里就不多贅述了。

那么考慮如何求出最小正原根,因為原根的數量大約有φ(φ(p))\varphi(\varphi (p))φ(φ(p))個,所以密集度比較高,據說最小正原根約是O(n2.5)O(n^{2.5})O(n2.5)級別的。

所以考慮直接枚舉,但是我們判定的時候肯定不能從1~φ(p)1\sim \varphi(p)1φ(p)枚舉來判斷。

我們還需要用到一個結論就是如果對于gcd(a,p)=1gcd(a,p)=1gcd(a,p)=1ak≡1(modp)a^k\equiv 1(mod\ p)ak1(mod?p)(也就是kkkaaannn的階),那么有k∣φ(p)k|\varphi(p)kφ(p)。所以我們需要判定φ(p)\varphi(p)φ(p)的所有因子?看起來還是很大,但是我們顯然有ak≡1(modp)a^k\equiv 1(mod\ p)ak1(mod?p)那么akx≡1(modp)a^{kx}\equiv1(mod\ p)akx1(mod?p)其中x∈N+x\in N^+xN+。所以我們只需要枚舉φ(p)k\frac{\varphi(p)}{k}kφ(p)?(其中kkkφ(p)\varphi(p)φ(p)的質因子)即可,因為這些數包含了其他數的倍數。

時間復雜度O(n0.25log?n)O(n^{0.25}\log n)O(n0.25logn)


code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const ll N=1e6+10; ll T,n,d,cnt,phi[N],pri[N]; bool v[N],rt[N]; vector<int> q; void prime(){phi[1]=1;for(ll i=2;i<N;i++){if(!v[i])pri[++cnt]=i,phi[i]=i-1;for(ll j=1;j<=cnt&&i*pri[j]<N;j++){v[i*pri[j]]=1;if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}phi[i*pri[j]]=phi[i]*phi[pri[j]];}}rt[2]=rt[4]=1;for(ll i=2;i<=cnt;i++){for(ll j=1;j<N;j*=pri[i])rt[j]=1;for(ll j=2;j<N;j*=pri[i])rt[j]=1;}return; } ll power(ll x,ll b,ll p){ll ans=1;while(b){if(b&1)ans=ans*x%p;x=x*x%p;b>>=1;}return ans; } ll gcd(ll x,ll y) {return (!y)?x:gcd(y,x%y);} void dec_phi(ll x){for(ll i=1;i<=cnt&&pri[i]*pri[i]<=x;i++)if(x%pri[i]==0){q.push_back(pri[i]);while(x%pri[i]==0)x/=pri[i];}if(x!=1)q.push_back(x);return; } bool check(ll x){if(power(x,phi[n],n)!=1)return 0;for(ll i=0;i<q.size();i++)if(power(x,phi[n]/q[i],n)==1)return 0;return 1; } signed main() {scanf("%lld",&T);prime();while(T--){scanf("%lld%lld",&n,&d);q.clear();if(!rt[n]){printf("0\n\n");continue;}dec_phi(phi[n]);ll g=1;while(!check(g))g++;ll tmp=1;q.clear();for(ll i=1;i<=phi[n];i++){tmp=tmp*g%n;if(gcd(phi[n],i)==1)q.push_back(tmp);}printf("%lld\n",q.size());sort(q.begin(),q.end());for(ll i=1;i<=q.size()/d;i++)printf("%lld ",q[i*d-1]);putchar('\n');}return 0; }

總結

以上是生活随笔為你收集整理的P6091-[模板]原根的全部內容,希望文章能夠幫你解決所遇到的問題。

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