1. 程式人生 > >ACM-ICPC 2018 南京賽區網路預賽 J. Sum(篩法+分塊)

ACM-ICPC 2018 南京賽區網路預賽 J. Sum(篩法+分塊)

題目連結傳送門

 

題意:給你一個數字n,讓你求從1到n的每個數的乘數組合的個數,要求乘數滿足不能被平方數整除。

 

解決方法:比賽的時候想到用線性篩來先將不符合的數先標記出來,然後再去便利統計個數。一開始t了,後來改成分塊後因為程式碼寫挫wa了好多次,還是自己太菜了。

下面附上比賽ac程式碼

 

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 21000010;
long long tag[21000010];
long long prime[21000010];
long long sum[21000010];
void Prime() {
	memset(tag, 0, sizeof(tag));
	int cnt = 0;
	tag[0] = tag[1] = 1;
	for (long long i = 2; i <= sqrt((double)maxn); i++) {
		if (tag[i] == 1) continue;
		prime[cnt++] = i*i;
		tag[i*i] = 1;
	}
	for (long long j = 0; j < cnt; j++) {
		for (long long i = 2; i*prime[j] < maxn; i++) {
			tag[i*prime[j]] = 1;
		}
	}
}
int main(void) {
	int t;
	scanf("%d", &t);
	Prime();
	tag[1] = 0;
	sum[0] = 0;
	for (int i = 1; i < maxn-1; i++) {
		sum[i] += sum[i - 1]+tag[i];
	}
	while (t--) {
		long long a, b;
		scanf("%lld", &a);
		if (a <= 0) {
			printf("0\n");
		}
		long long tot= 0;
		for (long long i = 1; i <= a; ) {

			if (tag[i] != 1) {
				int t = a / (a / i);
				tot += (a / i - sum[a / i])*(t-i+1-(sum[t]-sum[i]));
				i = t + 1;
			}
			else i++;
		}
		printf("%lld\n", tot);
	}
	return 0;
}