B - 不知道现在的女孩子都喜欢什么数字-Hard

Description

本题和Easy的区别仅体现在数据范围不同,请认真分析做法的时间复杂度。

yuyansheng给自己算命的时候得到了一个神奇的数字 d ,我们称 d 为相性值,每个人都有自己喜欢的数字,如果两个人喜欢的数字的最大公约数等于这个数字 d ,那么我们称这两个人为有缘人。因为太大的数记起来有点麻烦,所以我们假设大家喜欢的数有一个上限 n ,那么我们把所有的女孩纸分为 n 类,喜欢数字 i 的女孩纸为第 i 类女孩纸。现在给定女孩子总数 n ,yuyansheng喜欢的数字 x ,和相性值 d ,吃瓜出题人想知道到底有多少女孩纸和yuyansheng有缘。

换言之,出题人想知道1~n 中与 x 的最大公约数为 d 的数的个数。

Input

输入的第一行是三个正整数 n ,x(1≤n≤1016,1≤x≤109) ,d (104≤d≤105),表示女孩子总数n,yuyansheng喜欢的数字x,和相性值d(题目保证 x 一定是 d 的倍数,样例仅供理解题目意思,保证测试数据符合规定)。

Output

输出一行 11 个数,表示有多少的女孩纸和yuyansheng有缘。

Sample

Input 

10 6 2

Output 

4

Hint

分别是2,4,8,10

#include 
using namespace std;
#define int long long
const int N = 1e6 + 5;
vector g;
int fun(int n, int m)//n为x,m为1-m及区间
{
	//n不一定为质数
	//分解其为质因数
	//然后1-m中含有这些质因数的与其不互质
	//最后用区间长度减去与其互质的量
	//就为与其不互质的量
	g.clear();
	for (int i = 2; i <= n / i; i++)
	{
		if (n % i == 0)
		{
			g.push_back(i);
			while (n % i == 0)
				n /= i;
		}
	}
	if (n > 1)
		g.push_back(n);
	int S = 0;
	for (int i = 1; i < (1 << g.size()); i++)
	{
		int cnt = 0;
		int mul = 1;
		for (int j = 0; j < g.size(); j++)
		{
			if (i >> j & 1)
			{
				cnt++;
				mul *= g[j];
			}
		}
		if (cnt & 1)
			S += m / mul;
		else
			S -= m / mul;
	}
	return m - S;
}
signed main()
{
	int n, x, d;
	cin >> n >> x >> d;
	n /= d, x /= d;
	int ans = fun(x, n);
	cout << ans << endl;
	return 0;
}

你可能感兴趣的:(c++,算法,开发语言)