本文主要是介绍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));}
}
这篇关于HDU 4279 Number [数论+简证]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!