欧拉函数模板

那年仲夏 提交于 2019-11-30 08:08:59

洛谷P3601 签到题

数论里面,对于 l 和 r 很大,r-l 范围又很小的时候,都用到了用一个数组x[ i ]表示 i+l 的值,也就是把 l~r 这个区间对应到 0~l-1 中了。

同时也预处理了可能对答案做出贡献的值(一般是预处理根号内的素数)。

与这道题很相似:

洛谷P1835 素数密度_NOI导刊2011提高(04)

 

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define ll long long
#define ri register int
int cnt=0,ans=0,pri[N],su[N],fl[N];
ll l,r;
void suu(int n)
{
    for(ri i=2;i<=n;++i){
        if(!pri[i]) su[++cnt]=i;
        for(ri j=1;j<=cnt&&su[j]*i<=n;++j){
            pri[su[j]*i]=1;
            if(i%su[j]==0) break;
        }
    }
}
int main()
{
    scanf("%lld%lld",&l,&r);
    suu(sqrt(r));
    for(int i=1;i<=cnt;++i){
        for(ll j=l/su[i]*su[i];j<=r;j+=su[i]){
            if(j>=l && j!=su[i]) fl[j-l]=1;
        }
    }
    for(ll i=l;i<=r;++i) if(fl[i-l]==0) ans++;
    printf("%d\n",ans);
}
/*
2 11
*/
筛大素数

 

这道题也是一样,已知求单个欧拉的公式与其质因子有关,就预处理出 1~sqrt(r)的素数,然后枚举素数进行更新。

(注意题中要求的是与其不互质的数,用它本身减一下就行了)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 666623333
#define N 1000005
ll l,r,su[N],phi[N],pri[N],tmp[N],cnt=0;
void init()
{
    ll x=sqrt(r);
    for(ll i=2;i<=x;++i){
        if(!pri[i]) su[++cnt]=i;
        for(ll j=1;j<=cnt&&su[j]*i<=x;++j){
            pri[su[j]*i]=1;
            if(i%su[j]==0) break;
        }
    }
}
void calc_phi()
{
    for(ll i=0;i<=r-l;++i) tmp[i]=i+l,phi[i]=i+l;
    for(ll i=1;i<=cnt;++i){
        ll ln=l/su[i]*su[i],rn=r/su[i]*su[i];
        for(ll j=ln;j<=rn;j+=su[i]){//很像筛大素数的思路 预处理出可能做出贡献的值 跳着更新 把时间降到nlogn 
            if(j<l) continue;
            phi[j-l]=phi[j-l]/su[i]*(su[i]-1);//利用公式计算 
            while(tmp[j-l]%su[i]==0) tmp[j-l]/=su[i];
        }
    }
    for(ll i=0;i<=r-l;++i) 
    if(tmp[i]>1) phi[i]=phi[i]/tmp[i]*(tmp[i]-1);
}
int main()
{
    ll ans=0;
    scanf("%lld%lld",&l,&r);
    init();
    calc_phi();
    for(ll i=0;i<=r-l;++i) ans=(ans+i+l-phi[i])%mod;
    printf("%lld\n",ans);
}
/*
233 2333
*/
签到题

 

P5091 【模板】欧拉定理

求a^m %mod 的时候,m过大,就可以由欧拉定理将m变成一个小于mod的数:

 

 

图片来源

然后就是一个裸的板子了:

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll phi,fl=0;
ll read()
{
    ll x=0; char ch=getchar();
    while(ch<'0'||ch>'9'){ if(ch=='-') fl=-1; ch=getchar(); }
    while(ch<='9'&&ch>='0'){
        x=(x*10+ch-'0');
        if(x>=phi) fl=1,x%=phi;
        ch=getchar();
    } 
    return x;
}
ll quick_pow(ll a,ll k,ll mod)
{
    ll ans=1;
    while(k){ if(k&1) ans=ans*a%mod; a=a*a%mod; k>>=1; }
    return ans;
}
ll calc_phi(ll x)//求单个欧拉 
{
    ll ans=x;
    for(ll i=2;i<=sqrt(x);++i)
    if(x%i==0){
        ans=ans/i*(i-1);
        while(x%i==0) x/=i;
    }
    if(x>1) ans=ans/x*(x-1);
    return ans;
}
int main()
{
    ll a,m,b;
    scanf("%lld%lld",&a,&m);
    phi=calc_phi(m);
    b=read();
    printf("%lld\n",quick_pow(a,b+fl*phi,m));
}
/*
998244353 12345 98765472103312450233333333333
*/
欧拉定理

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!