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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ - 2186 欧拉函数

發(fā)布時間:2023/11/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ - 2186 欧拉函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目的意思大概是求1~N!中和M!互質(zhì)的數(shù)的個數(shù)

因?yàn)閷W拉函數(shù)理解不夠深刻所以我是分析得到結(jié)果的:

當(dāng)N<=M的時候顯然符合要求的數(shù)的個數(shù)為0;

當(dāng)N>M的時候我們要求的是1~N!中不含1 ~M的素因子的的數(shù)的個數(shù),結(jié)合歐拉函數(shù)的推導(dǎo)過程(容斥原理)假設(shè)N!在1 ~ M中含有k個素因子,設(shè)n=N!,那么符合要求的數(shù)的個數(shù)就是

n?n/p1?n/p2?...?n/pk+n/p1p2+n/p1p3+...+n/p(k?1)pk?...=n(1?1/p1)(1?1/p2)...(1?1/pk)n-n/p1-n/p2-...-n/pk+n/p1p2+n/p1p3+...+n/p(k-1)pk-...=n(1-1/p1)(1-1/p2)...(1-1/pk)n?n/p1?n/p2?...?n/pk+n/p1p2+n/p1p3+...+n/p(k?1)pk?...=n(1?1/p1)(1?1/p2)...(1?1/pk)
因?yàn)槲覀儾荒苁紫惹蟪鰊的大小再算(如果可以求出n的大小的話那顯然直接計(jì)算就可以,但是我們必須要模R),在模R的情況下我們應(yīng)該求出pi的逆元,所以整個過程就是線性篩得到1~M的素數(shù)因子以及他們的逆元,然后與N!相乘計(jì)算(按照上面的公式)

我的代碼:

#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<cmath> #include<ctime> #include<climits> #include<queue> #include<vector> #include<set> #include<map> using namespace std;typedef long long ll; const int INF=0x3f3f3f3f; const int MAXN=1e7+5; int prime[MAXN]; bool check[MAXN]; int N[MAXN],r[MAXN],ans[MAXN]; int tot; ll R,n,m;void ex_gcd(int a,int b,int& d,int &x,int &y) {if(!b) {d=a; x=1; y=0;}else{ex_gcd(b,a%b,d,y,x); y-=(a/b)*x;} }int getine(int a) {int x,y,d;ex_gcd(a,R,d,x,y); x=(x%R+R)%R;return x; }void creat_prime() {tot=0; r[1]=1; N[1]=1;for(int i=2;i<MAXN;i++){N[i]=(ll)N[i-1]*i%R;if(!check[i]){prime[tot++]=i;r[i]=getine(i);}for(int j=0;j<tot && prime[j]*i<MAXN;j++){check[prime[j]*i]=true;if(i%prime[j]==0) break;}} }void init() {ans[1]=1;for(int i=2;i<MAXN;i++){ans[i]=ans[i-1];if(!check[i]) ans[i]=(ll)ans[i]*(i-1)%R*r[i]%R;} }int main() {int T;scanf("%d%d",&T,&R);creat_prime();init();while(T--){scanf("%d%d",&n,&m);printf("%d\n",(ll)N[n]*ans[m]%R);}return 0; }

雖然可以得到正確的答案,但是經(jīng)過了自己的推導(dǎo)分析,思維質(zhì)量比較低。根本原因還是對歐拉函數(shù)的理解不夠深刻。

讓我們再來看看歐拉函數(shù)的意義:求出1~n中和n互質(zhì)的數(shù)的個數(shù),那么1 ~kn中與n互質(zhì)的數(shù)的個數(shù)有多少呢?答案是k*phi[n](結(jié)合上面推導(dǎo)也可以發(fā)現(xiàn)這個)。為什么是這樣呢?

互質(zhì)即意味著gcd(x,n)=1gcd(x,n)=1gcd(x,n)=1,由最大公約數(shù)的性質(zhì)我們得到gcd(x+kn,n)=1gcd(x+kn,n)=1gcd(x+kn,n)=1即這個數(shù)在每次kn+1~(k+1)n中都會出現(xiàn)一次,所以答案是k*phi[n]

回到這個問題:題目要求1~N!中和M!互質(zhì)的數(shù)的個數(shù),那么答案應(yīng)該是N!/M!*phi[M!],再結(jié)合歐拉函數(shù)值的求法可以得到上面的過程。

學(xué)習(xí)了一下遞推法求逆元.(遞推法求逆元如果不是都要用時間還是慢一點(diǎn))

#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<cmath> #include<ctime> #include<climits> #include<queue> #include<vector> #include<set> #include<map> using namespace std;typedef long long ll; const int INF=0x3f3f3f3f; const int MAXN=1e7+5; int prime[MAXN]; bool check[MAXN]; int N[MAXN],r[MAXN],ans[MAXN]; int tot; ll R,n,m;int read() {int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x; }void ex_gcd(int a,int b,int& d,int &x,int &y) {if(!b) {d=a; x=1; y=0;}else{ex_gcd(b,a%b,d,y,x); y-=(a/b)*x;} }int getine(int a) {int x,y,d;ex_gcd(a,R,d,x,y); x=(x%R+R)%R;return x; }void creat_prime() {tot=0; r[1]=1; N[1]=1;for(int i=2;i<MAXN;i++){N[i]=(ll)N[i-1]*i%R;if(!check[i]){prime[tot++]=i;//r[i]=getine(i);}for(int j=0;j<tot && prime[j]*i<MAXN;j++){check[prime[j]*i]=true;if(i%prime[j]==0) break;}}for(int i=2;i<MAXN&&i<R;i++)r[i]=R-(ll)R/i*r[R%i]%R; }void init() {ans[1]=1;for(int i=2;i<MAXN;i++){ans[i]=ans[i-1];if(!check[i]) ans[i]=(ll)ans[i]*(i-1)%R*r[i]%R;} }int main() {int T;T=read(); R=read();creat_prime();init();while(T--){n=read(); m=read();printf("%d\n",(ll)N[n]*ans[m]%R);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的BZOJ - 2186 欧拉函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。