题解:
——t 小 n 大,适合用单个求欧拉值模板
单求欧拉函数通式:
——求 x 的欧拉函数值
φ ( x ) = x * ( 1 - 1 / p1 ) * ( 1 - 1 / p2 ) * ( 1 - 1 / p3 ) * ( 1 - 1 / p4 ) … ( 1 - 1 / pn )
pi表示的是啥?
答:将 x 质因数拆分后,pi 表示拆分后不同质因数。
n 表示 x 进行拆分后得到的不同质因数的个数,不用管具体是几。
举个例子:
x = 20 = 2 * 2 * 5
n = 2(2和5)
p1 = 2 (质数2)
p2 = 5 (质数5)
注意:
φ ( 1 ) = 1.
时间复杂度:O(x)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll phi(ll n)
{
ll i,rea=n;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
rea=rea-rea/i;//等价于rea * ( 1 - 1 / i )
while(n%i==0)
n/=i;
}
}
if(n>1) rea=rea-rea/n;
return rea;
}
void solve()
{
ll n;
scanf("%lld",&n);
printf("%lld\n",phi(n));
}
int main()
{
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}
题意不变,范围变化了
题解:
——t 大 n 小,适合打表模板
如何理解打表模板:
——注意看通式中的它:
( 1 - 1 / pi ) = ( pi - 1) / pi.【pi 为素数】
——接下来运用素数筛的思维模式:
找到素数 i ,遍历 i 的倍数,根据欧拉函数通式,被找的倍数是一定要乘一次 ( i - 1) / i 的。
代码1:欧拉函数打表(类似埃氏筛)
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6;
int phi[MAXN+1];
void getEuler()
{
memset(phi,0,sizeof(phi));
phi[1]=1;//1的欧拉值为1
for(int i=2;i<=MAXN;i++)
{
if(!phi[i])
{
for(int j=i;j<=MAXN;j+=i)
{
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
void solve()
{
int n;
scanf("%d",&n);
printf("%d\n",phi[n]);
}
int main()
{
getEuler();
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}
代码2:素数和欧拉一起打表的模板(线性筛)
//求1e6以内的素数和欧拉函数
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6;
int book[MAXN+1],prime[MAXN+1],cnt;
int phi[MAXN+1];
void getPrimeEuler()
{
cnt=0;
memset(book,0,sizeof(book));
book[0]=book[1]=1;
phi[1]=1;
for(int i=2;i<=MAXN;i++)
{
if(!book[i])
{
prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&prime[j]<=MAXN/i;j++)
{
book[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
void solve()
{
int n;
scanf("%d",&n);
printf("%d\n",phi[n]);
}
int main()
{
getPrimeEuler();
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}
/*
有三条特性:
若a为质数 phi[a]=a-1;
若a为质数,b%a==0 phi[a*b]=phi[b]*a;
若a b互质 ph[a*b]=phi[a]*phi[b](当a为质数 如果b%a!=0)
*/