题目链接https://nanti.jisuanke.com/t/A1956

 

题目大意:就是找一个数拆成两个无平方因子的组合数,然后求个前缀和。

分析:

0.如果一个数是质数,毫无疑问ans[i]=2;

1.如果一个数某个质因子的指数大于等于3,那么无论怎么分,至少有一边的数里面含有平方因子,所以ans[i]=0;

2.如果一个数k的某个质因子p的指数是1,这个1要么给左边,要么给右边,所以ans[k]=ans[k/p]*2=ans[k/p]*ans[p];

3.如果一个数k的某个质因子p的指数是2,只能左右各一个,所以ans[k]=ans[k/(p*p)];

在线性筛中,每个数只会被它的最小质因子筛掉

#include<cstdio>
using namespace std;
typedef long long ll;
const int N=2e7+5;
int ans[N];
int prime[N],cnt=0;
bool book[N];
void init(){
	ans[1]=1;
	for(int i=2;i<N;i++){
		if(!book[i]){
			prime[cnt++]=i;
			ans[i]=2;
		}
		for(int j=0;j<cnt;j++){
			int k=(ll)i*prime[j];
			if(k>=N) break;
			book[k]=true;
			if(i%prime[j]!=0) ans[k]=ans[i]*ans[prime[j]];//k中prime[j]的指数为1
			else{
				int t=prime[j]*prime[j];
				if(i%t==0) ans[k]=0;//k中prime[j]的指数大于等于3
				else ans[k]=ans[k/t];//k中prime[j]的指数等于2
				break;
			}
		}
	}
	for(int i=1;i<N;i++)
	ans[i]+=ans[i-1];
}
int main(){
	init();
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d",&n);
		printf("%d\n",ans[n]);
	}
	return 0;
}