HDU 4279 Number [数论+简证]

题意: 给出一个f(x), 表示不大于x的正整数里,不整除x 且 跟x有大于1的公约数 的数的个数。定义F(x), 为不大于x的正整数里,满足f(x)的值为奇数的数的个数。题目就是求这个F。

分析:

打表找规律的方法我就不说了。这里我们来简单推理证明下。

先来看f(x),“不整除x” 等同于 不是x的约数,“跟x有大于1的公约数” 等同于 不是x的互质数。而且从F的定义知道,我们只需要考虑f(x)的奇偶性即可。

所以, f(x) = x - 约数个数 - 互质数个数 +1 。最后+1是因为,1是约束也是互质数,减了两次所以补回来。

约数个数,我们由基本定理可得,x可写成质数幂累乘的形式,而由计数方法易知 x的约数个数为 (质数的幂+1)的累乘。所以若要使约数为奇数,充要条件是(质数的幂+1)都为奇数,即质数的幂都为偶数。所以此时 x必然是一个平方数。综上,x为平方数,其约数个数为奇数;x为非平方数,其约数个数为偶数

互质数个数,我们自然联想到欧拉函数。

欧拉函数的值为 不大于n的正整数中与n互质的数的个数。这不就是互质数个数么?而且可以证明,欧拉函数在n>2时,值都为偶数。

所以,当x>2时, 若x为平方数,f(x)=x-奇-偶+1,要使f(x)为奇数,则x必为奇数;若x为非平方数,f(x)=x-偶-偶+1,要使f(x)为奇数,则x必为偶数。 当x=1或2时,f(x)=0.

综上,F(x)的值为[3,x]中,奇数平方数+偶数非平方数的个数和,即 偶数个数-偶数^2的个数+奇数^2的个数

而偶数个数为 x/2-1,-1是为了把2减掉。偶数^2个数为 sqrt(x)/2,奇数^2个数为 ( sqrt(x)-(sqrt(x)/2) )-1,这里-1是为了把1减掉。

所以,化简后,F(x) = x/2-1+(sqrt(x)%2? 0: -1).

至此推证完毕。

另外,这题不管我怎么改,用C++交始终是wa(无力吐槽杭电的int64)。。不知道为什么,如果有人有C++能AC的代码,麻烦提供一下,非常感谢~

还有一点就是,x要转成long double后再开根号,或者直接 x*1.0 。用double会wa。。


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef __int64 int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

int64 f(int64 x)
{
	if(x<=2) return 0;
	//return x/2-1+( (int64)floor(sqrt((double)x)) %2? 0: -1);			//用 double wa。
	//return x/2-1+( (int64)floor(sqrt((long double)x)) %2? 0: -1);		//floor 可不用。
	return x/2-1+( (int64)sqrt((long double)x) %2? 0: -1);		//用 long double 或者 *1.0
}

int main()
{
	int T = Rint();
	while(T--)
	{
		int64 a, b;
		scanf("%I64d%I64d", &a, &b);
		printf("%I64d\n", f(b)-f(a-1));
	}
}


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页