ACM-ICPC 2018 南京赛区网络预赛 J-Sum

ACM-ICPC 2018 南京赛区网络预赛 J-Sum

题目链接:ACM-ICPC 2018 南京赛区网络预赛 J-Sum

题意

         \;\;\;\; f [ i ] f[i] f[i] 表示有序整数对 ( a , b ) (a,b) (a,b),满足 a b = i ab=i ab=i 的数量。
             \;\;\;\;\;\; eg: f [ 6 ] = 4 f[6] = 4 f[6]=4 6 = 1 ⋅ 6 = 6 ⋅ 1 = 2 ⋅ 3 = 3 ⋅ 2 6 = 1 \cdot 6 = 6 \cdot 1 = 2 \cdot 3 = 3 \cdot 2 6=16=61=23=32.

         \;\;\;\; f f f 的前 n n n 项和。

         \;\;\;\; 1 ≤ T ≤ 20 , 1 ≤ n ≤ 2 ∗ 1 0 7 1 \leq T \leq 20, 1 \leq n \leq 2*10^{7} 1T20,1n2107.

思路一(欧拉筛)

         \;\;\;\; 欧拉筛的思路:每个数被其最小素因子标记。
         \;\;\;\; 将一个数质因子分解: n = p 1 e 1 ⋅ p 2 e 2 ⋅ p 3 e 3 . . . n = p_{1}^{e_{1}} \cdot p_{2}^{e_{2}} \cdot p_{3}^{e_{3}}... n=p1e1p2e2p3e3... ,在其所有的指数 e 1 , e 2 , e 3 . . . e_{1},e_{2}, e_{3}... e1,e2,e3... 中:
             \;\;\;\;\;\; e i = 1 e_{i} =1 ei=1,那么 p i p_{i} pi 可以放在 a a a b b b 中,对 f [ n ] f[n] f[n] 贡献为 × 2 \times2 ×2
             \;\;\;\;\;\; e i = 2 e_{i} =2 ei=2,那么 p i p_{i} pi 必须拆开,一个放在 a a a 中,另一个放在 b b b 中,对 f [ n ] f[n] f[n] 贡献为 × 1 \times1 ×1
             \;\;\;\;\;\; e i > 2 e_{i} >2 ei>2,那么 p i p_{i} pi 无论怎么拆分,在 a a a b b b 中总会有平方数或其倍数,这时 f [ n ] = 0 f[n] = 0 f[n]=0.

代码一

/*
nero
https://nanti.jisuanke.com/t/A1956
c[i]记录最小质因子的指数 
*/
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
 
using namespace std;
 
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
 
const int MAXN = 20000005;
const ll Mod = 1000000007;
#define MOD(a, b) a>=b?a%b+b:a

int prime[MAXN], c[MAXN];
ll f[MAXN];
bool Isprime[MAXN];
void Init(){
	int N = MAXN-5, cnt = 0;
	f[1] = 1;
    for(int i = 2; i <= N; i++){
    	if(!Isprime[i]) {
    		prime[++cnt] = i;	
    		f[i] = 2;
    		c[i] = 1;
		}
		for(int j = 1; j <= cnt && (ll)i*prime[j] <= N; j++) {
			int x = i*prime[j];
			Isprime[x] = 1;
			
			if(i%prime[j] == 0) {
				c[x] = c[i] + 1;
				if(c[x] == 2) { // 指数为 2  
					f[x] = f[i/prime[j]];
				}
				else { 			// 指数 > 3  
					f[x] = 0;
				}
				break;
			} 
			else {		// 指数为 1 
				c[x] = 1; // WA c[x] = c[i] 
				f[x] = f[i] * 2;
			}
    	}
	}
	for(int i = 1; i <= N; i++) {
		f[i] += f[i-1];
	}
}
int main() {
	Init();
	int T, n;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		printf("%lld\n", f[n]);
	}
    return 0;
}
/*

*/

思路二(数论)

         \;\;\;\; 要求 ∑ i = 1 n a b = i \sum_{i=1}^{n}ab=i i=1nab=i,即求 ∑ a b ≤ n \sum ab \leq n abn. 比如:当 n = 30 , a = 3 n=30, a=3 n=30,a=3 时, 30 / 3 = 10 30/3=10 30/3=10,即有 10 10 10 b ( 1 − 10 ) b(1-10) b(110) 满足条件,再删掉其中的平方数以及它们的倍数即可。
         \;\;\;\; s u m [ i ] sum[i] sum[i] 表示前 i i i 数中有多少个数不含平方数因子, p [ i ] p[i] p[i] 表示第 i i i 个不含平方数因子的数, 则 a n s = ∑ s u m [ n / p i ] ans = \sum sum[n/p_{i}] ans=sum[n/pi].

代码二

/*
nero
https://nanti.jisuanke.com/t/A1956
bo[j]=0 表示数 j 不含平方数因子 
sum[i] 表示前i个数里面有多少个数不含平方数因子 
p[i] 表示第i个不含平方数因子的数 
*/
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
 
using namespace std;
 
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
#define MOD(a, b) a>=b?a%b+b:a
typedef long long ll;
typedef unsigned long long ull;
 
const int MAXN = 20000005;
const ll Mod = 1000000007;

int sum[MAXN], p[MAXN], cnt;
bool bo[MAXN];
void Init(){
	int N = MAXN-5;
    for(int i = 2; i <= N; i++){
    	ll x = i*i;
    	if(x > N) break;
    	for(int j = x; j <= N; j+=x) {
    		bo[j] = 1;
		}	
	}
	for(int i = 1; i <= N; i++) {
		if(bo[i]) {
			sum[i] = sum[i-1];
		}
		else {
			p[++cnt] = i;
			sum[i] = sum[i-1] + 1;
		}
	}
}
int main() {
	Init();
	int T, n, ans;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		ans = 0;
		for(int i = 1; i <= cnt && p[i] <= n; i++) {
			int idx = n/p[i];
			ans += sum[idx];
		}
		printf("%lld\n", ans);
	}
    return 0;
}
/*
*/

参考:
ACM-ICPC 2018 南京赛区网络预赛 Sum(线性筛)
ACM-ICPC 2018 南京赛区网络预赛 J.sum

好久没有写博客,忽然发现有了不同语言的代码片,好评!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值