题目大意:求1~n区间欧拉函数的个数。
思路:直接欧拉函数的递推式的模板撸过~~做了这道题~~从此不再相信C++编译器了~~尼玛坑爹啊~~这道题~~C++RE,G++轻松撸过~~
关于欧拉函数的递推关系:
假设素数p能整除n,那么
如果p还能整除n / p, PHI(n) = PHI(n / p) * p;
如果p不能整除n / p, PHI(n) = PHI(n / p) * (p - 1);
AC program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define maxn 1000100
typedef __int64 LL;
LL ee[maxn];
void get_euler()
{
for(LL i=1;i<=maxn;i++)
ee[i]=i;
for(LL i=2;i<=maxn;i+=2)
ee[i]/=2;
for(LL i=3;i<=maxn;i+=2)
{
if(ee[i]==i)
{
for(LL g=i;g<=maxn;g+=i)
ee[g]=ee[g]/i*(i-1);
}
}
//cout<<ee[1]<<" "<<ee[2]<<endl;
ee[2]=1; //注意了
for(LL i=3;i<=maxn;i++)
{
ee[i]+=ee[i-1];
}
}
int main()
{
get_euler();
LL m;
while(cin>>m,m)
{
cout<<ee[m]<<endl;
}
//system("pause");
return 0;}
以下转载:
下面是两种求欧拉函数的不同编程方法:
/*==================================================*\
|递推求欧拉函数phi(i)
\*==================================================*/
for (i = 1; i <= maxn; i++) phi[i] = i;
for (i = 2; i <= maxn; i += 2) phi[i] /= 2;
for (i = 3; i <= maxn; i += 2) if(phi[i] == i) {
for (j = i; j <= maxn; j += i)
phi[j] = phi[j] / i * (i - 1);
/*==================================================*\
|单独求欧拉函数phi(x)
\*==================================================*/
unsigned euler(unsigned x)
{// 就是公式
unsigned i, res=x;
for (i = 2; i < (int)sqrt(x * 1.0) + 1; i++)
if(x%i==0) {
res = res / i * (i - 1);
while (x % i == 0) x /= i; // 保证i一定是素数
}
if (x > 1) res = res / x * (x - 1);
return res;
}
另转载一篇有特色的做法:
思路: 在生成素数的同时,完成欧拉函数。
daima:
#include <stdio.h> #define MAX 1000000 int n,p[MAX],a[MAX]; long long f[MAX]; void prim1(){for(int i = 1;i <=MAX;i++) p[i] = 0; for(int i=1;i<=MAX;i++) a[i]=i; for(int i = 2;i <=MAX;i++) { if(!p[i]) { for(int j=i;j<=MAX;j+=i) { p[j] =1; a[j] = a[j]/i*(i-1); } } } return ; } void prim2(){ int i; prim1(); f[2]=1; for(i=3;i<=MAX;i++) { f[i]=f[i-1]+a[i]; }
} int main(){prim2(); while(1) { scanf("%d",&n); if(!n) break; printf("%lld\n",f[n]); } return 0;
}
再转一篇用筛选法做的~~给跪了~~我的筛法弱爆了~~
#include<iostream>
using namespace std;
//欧拉函数的应用,注意筛法在欧拉函数中的变型应用
__int64 a[1000002]={0};//存放数的互质个数
__int64 b[1000002]={0};//存放结果,这里有一个递推关系b[i]=b[i-1]+a[i];
__int64 c[1000002]={0};//标记数组
__int64 prime[200002]={0},len,n;
__int64 slove1()//素数筛法
{
__int64 i,j,temp;
len=0;
for(i=2;i<=1000000;i++)
{
if(!c[i])prime[len++]=i;
for(j=0;j<len&&prime[j]*i<=1000000;j++)
{
c[prime[j]*i]=1;//不是质数
if(i%prime[j]==0)break; //
}
}
}
//如果p还能整除n / p, a(n) = a(n / p) * p;
//如果p不能整除n / p, a(n) = a(n / p) * (p - 1);
void slove2()
{
__int64 i,j,k;//欧拉函数进行类似素数筛法的处理
a[1]=1;
for(i=2;i<=1000000;i++)
{
if(!c[i])//是质数
{
a[i]=i-1;continue;
}
for(j=0;j<len&&prime[j]*prime[j]<=1000000;j++)
{
if(i%prime[j]==0)
{
if(i/prime[j]%prime[j]==0)
{
a[i]=prime[j]*a[i/prime[j]];
}
else a[i]=(prime[j]-1)*a[i/prime[j]];
break;//
}
}
}
}
void slove3()
{
__int64 i,j,k;
b[2]=1;
for(i=3;i<=1000000;i++)
{
b[i]=b[i-1]+a[i];
}
}
int main()
{
slove1();
slove2();
slove3();
while(scanf("%I64d",&n)!=EOF)
{
if(n==0)break;
printf("%I64d\n",b[n]);
}
return 0;
}
再转一篇线性的做法:
#include<iostream>
using namespace std;
const int MAX=1001000;
int pri[MAX/3],pn=0;
char notp[MAX]={0};
int phi[MAX];
__int64 sum[MAX];
void phif(void)
{
for(int i=2;i<MAX;i++){
if(notp[i]==0){
pri[pn++]=i;
phi[i]=i-1;
}
for(int j=0;j<pn&&MAX>pri[j]*i;j++){
notp[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
else
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
}
int main(void)
{
phif();
int n;
sum[2]=phi[2];
for(int i=3;i<=1000000;i++)
sum[i]=sum[i-1]+phi[i];
while(1){
scanf("%d",&n);
if(n==0)
break;
printf("%I64d\n",sum[n]);
}
return 0;
}