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("
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Zhi-71/p/10549834.html