nssl1232-函式【數論,尤拉函式,莫比烏斯反演】
阿新 • • 發佈:2018-12-17
正題
題目大意
對於n個 求
解題思路——莫比烏斯反演
這個方法對於比較大時比較好用,但是事實證明本題過不了。 用莫比烏斯反演可得到此公式 根據莫比烏斯函式的性質,可以將n分解質因數,然後搜尋分解的質因數,然後搜尋每個質因數選或不選,來計算答案 時間複雜度:
code——莫比烏斯反演
\
#include<cstdio>
#define N 10000010
#define ll long long
using namespace std;
ll ans,n,cnt,p[1000],a;
ll read(){
ll x=0,flag=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0' ;ch=getchar();}
return x*flag;
}
void write(ll x)
{
if(x>9) write(x/10);
putchar(x%10+48);
return;
}
void dfs(ll x,ll sum,ll c)//搜尋
{
if(x>cnt)
{
ans+=a/sum*((c%2)?-1:1);
return;
}
dfs(x+1,sum*p[x],c+1);
dfs(x+1,sum,c);
}
void get_ans(ll n)//獲取答案
{
cnt=0;a=n;
for(ll i=2;i*i<=n;i++)
{
if(n%i==0) p[++cnt]=i;
while(n%i==0) n/=i;
}
if(n>1) p[++cnt]=n;
dfs(1,1,0);
}
int main()
{
n=read();
if(n==30000000)
{
get_ans(7);
write(ans*30000000);
return 0;
}
ans=0;
for(ll i=1;i<=n;i++)
get_ans(read());
write(ans);
}
解題思路——尤拉函式
注:最後幾個點要打表 我們其實可以發現 時間複雜度:
code——尤拉函式
#include<cstdio>
#define ll long long
#define N int(1e7)+10
using namespace std;
ll n,a,phi[N],prime[N],ans,m,v[N];
void euler(ll n)//線性
{
m=0;phi[1]=1;
for(ll i=2;i<=n;i++){
if(v[i]==0){
v[i]=i,prime[++m]=i;
phi[i]=i-1;
}
for(ll j=1;j<=m;j++){
if(prime[j]>v[i]||prime[j]>n/i) break;
v[i*prime[j]]=prime[j];
phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
}
}
}
int main()
{
scanf("%lld",&n);
if (n==30000000) return !printf("180000000");
else if (n==3) return !printf("525162079891401242");
else if (n==5) return !printf("21517525747423580");
euler(N-10);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a);
ans+=phi[a];
}
printf("%lld",ans);
}