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; }