ACM-ICPC 2018 南京赛区网络预赛 J.sum(欧拉筛)
题目来源:https://nanti.jisuanke.com/t/A1956

题意:找一个数拆成无平方因子的组合数,然后求前缀和。
解题思路:我们可以把某个数分解质因数,如果某个数可以分解出三个相同的质数那么该f(n)=0,比如8=2*2*2, 24=2*2*2*3,所以f(8)=f(24)=0;如果该数是素数那么f(n)=2;并且我们可以发现,如果m,n互质,那么f(n*m)=f(n)*f(m);
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
#define ri register int
typedef long long ll;
inline ll gcd(ll i,ll j){
return j==0?i:gcd(j,i%j);
}
inline ll lcm(ll i,ll j){
return i/gcd(i,j)*j;
}
inline void output(int x){
if(x==0){putchar(48);return;}
int len=0,dg[20];
while(x>0){dg[++len]=x%10;x/=10;}
for(int i=len;i>=1;i--)putchar(dg[i]+48);
}
inline void read(int &x){
char ch=x=0;
int f=1;
while(!isdigit(ch)){
ch=getchar();
if(ch=='-'){
f=-1;
}
}
while(isdigit(ch))
x=x*10+ch-'0',ch=getchar();
x=x*f;
}
const int maxn=2e7+5;
int dis[maxn];
int prm[maxn];
int vis[maxn];
int sum[maxn];
void work(){
dis[1]=1;
for(int i=2;i<=2e7;i++){
if(vis[i]==0){
prm[++prm[0]]=i;
dis[i]=2;
}
for(int j=1;j<=prm[0]&&i*prm[j]<=2e7;j++){
// cout<<i<<" "<<prm[j]<<endl;
vis[i*prm[j]]=1;
if(i%prm[j]==0){
if(i%((ll)prm[j]*prm[j])==0){//说明i*prm[j]可以分解出三个相同的质因数
dis[i*prm[j]]=0;
}
else{
dis[i*prm[j]]=dis[i/prm[j]];
}
break;
}
dis[i*prm[j]]=dis[i]*dis[prm[j]];
}
}
sum[1]=1;
for(int i=2;i<=2e7;i++){
sum[i]+=sum[i-1]+dis[i];
}
}
int main(){
work();
int t;
read(t);
while(t--){
int n;read(n);
output(sum[n]);
printf("\n");
}
return 0;
}

浙公网安备 33010602011771号