UVa11876 - N + NOD (N)

I

N + NOD (N)

Input

Standard Input

Output

Standard Output

 

Consider an integer sequence N where,

N0 = 1
Ni = Ni-1 + NOD(Ni-1)- for i > 0

Here, NOD(x) =number of divisors of x.

So the first few terms of this sequence are 1 2 4 7 9 12 18…

Given two integers A and B, find out the number ofintegers in the above sequence that lies within the range [A, B].

Input

The first line of input is an integer T(T < 100000), thatindicates the number of test cases. Each case contains two integers, A followed by B (1 ≤ A ≤ B ≤ 1000000).

Output

For each case, output the case numberfirst followed by the required result.

 

Sample Input

Sample Output

3

1 18

1 100

3000 4000

Case 1: 7

Case 2: 20

Case 3: 87


刚开始在求出1000000内的所有满足条件的序列后,然后从a到b枚举有多少个,提交总是超时。后来改成在计算满足条件的序列时,用一个数组f记录到从0到n满足条件的个数,然后有f[b] - f[a-1]得到a到b区间内满足条件的数的个数。

#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <algorithm>

using namespace std;

const int N = 1100;
const int M = 65000;;
const int P = 200;
const int MAX = 1000001;

bool vis[N];
int a, b;
int vPrime[P], primeCnt;
int Ni[M], NiCnt;
int ans[MAX];

void input();
int solve();
void sieve_of_sundaram();
int cal(int n);
void init();

int main()
{
	#ifndef ONLINE_JUDGE
		freopen("d:\\OJ\\uva_in.txt", "r", stdin);
	#endif
	
	init();
	int t;
	scanf("%d", &t);
	for (int i = 1; i <= t; i++) {
		input();
		printf("Case %d: %d\n", i, solve());
	}
	return 0;
}

void sieve_of_sundaram()
{
	int m = (int)sqrt(N / 2);
	
	memset(vis, false, sizeof(vis));
	for (int i = 1; i < m; i++) {
		if (vis[i]) continue;
		for (int j = 2 * i * (i + 1), k = 2 * i + 1; j < N; j += k) {
			vis[j] = true;
		}
	}
	
	primeCnt = 0;
	vPrime[primeCnt++] = 2;
	for (int i = 1; i < N / 2; i++) {
		if (!vis[i]) vPrime[primeCnt++] = 2 * i + 1;
	}
	
}

int cal(int n)
{
	map<int, int> m;
	for (int i = 0; i < primeCnt; i++) {
		if (n < vPrime[i]) break;
		
		if (n % vPrime[i] == 0) {
			int cnt = 0;
			while (n % vPrime[i] == 0) {
				cnt++; 
				n /= vPrime[i];
			}
			m[vPrime[i]] = cnt;
		}
	}
	
	if (n != 1) m[n] = 1;
	
	int ans = 1;
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) {
		ans *= (it->second + 1);
	}
	
	return ans;
}

void init()
{
	sieve_of_sundaram();
	
	
	NiCnt = 0;
	Ni[NiCnt++] = 1;
	ans[0] = 0;
	ans[1] = 1;
	while (true) {
		int n = Ni[NiCnt - 1];
		int m = n + cal(n);
		if (m > 1000000) {
			fill(&ans[n], &ans[1000001], NiCnt);
			break;
		}
		fill(&ans[n], &ans[m], NiCnt);
		Ni[NiCnt++] = m;
	}
}

void input()
{
	scanf("%d%d", &a, &b);
}

int solve()
{
	return ans[b] - ans[a - 1];
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值