HDU 1695 GCD (欧拉函数+容斥原理)
GCD
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6446 Accepted Submission(s): 2356
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.
Yoiu can assume that a = c = 1 in all test cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
2 1 3 1 5 1 1 11014 1 14409 9
Case 1: 9 Case 2: 736427HintFor the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).题意: 在1~a, 1~b中挑出(x,y)满足gcd(x,y) = k , 求(x,y) 的对数 , a,b<=10^5
思路:x与y只有公因子k,则说明gcd(x/k,y/k)=1,我们令a/k>=b/k ,对于[1,a/k]中的i,如果i<=b/k,便 是求1~i-1中与i互质的个数,即求i的欧拉函数值。
对于i>a/k的情况,只有将i质因子分解,然后容斥原理了。(这题好像还可以用莫比乌斯反演下次写)
区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的乘积的倍数个数)-(区间中i的每4个质因数的乘积)+...
知识了解(by 百科):
欧拉函数
在数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。
φ函数的值 通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。 (注意:每种质因数只一个。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/3)=4。
若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。
欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。特殊性质:当n为奇数时,φ(2n)=φ(n), 证明与上述类似。
容斥原理
在计数时,必须注意无一重复,无一遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理
也可表示为设S为有限集, ,则两个集合的容斥关系公式:A∪B = A+B - A∩B (∩:重合的部分)三个集合的容斥关系公式:A∪B∪C = A+B+C - A∩B - B∩C - C∩A +A∩B∩C代码:View Code#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
const int MAXN = 100005;
int euler[MAXN+5];
void getEuler()
{
memset(euler,0,sizeof(euler));
euler[1] = 1;
for(int i = 2; i <= MAXN; i++)
if(!euler[i])
for(int j = i; j <= MAXN; j += i)
{
if(!euler[j])
euler[j] = j;
euler[j] = euler[j]/i*(i-1);
}
}
int prime[MAXN+1];
void getPrime()
{
memset(prime,0,sizeof(prime));
for(int i=2; i<=MAXN; i++)
{
if(!prime[i])prime[++prime[0]]=i;
for(int j=1; j<=prime[0]&&prime[j]<=MAXN/i; j++)
{
prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
long long factor[100][2];//factor[i][0]素因子,factor[i][1]素因子的个数
int fatCnt;
int getFactors(long long x)
{
fatCnt=0;
long long tmp=x;
for(int i=1; prime[i]<=tmp/prime[i]; i++)
{
factor[fatCnt][1]=0;
if(tmp%prime[i]==0)
{
factor[fatCnt][0]=prime[i];
while(tmp%prime[i]==0)
{
factor[fatCnt][1]++;
tmp/=prime[i];
}
fatCnt++;
}
}
if(tmp!=1)
{
factor[fatCnt][0]=tmp;
factor[fatCnt++][1]=1;
}
return fatCnt;
}
int cal(int a,int b)//求1~b中与a互质的个数
{
getFactors(a);
int ans = 0;
int maxn = 1 << fatCnt;
for(int i=1; i<maxn; i++)
{
int tmp = 1;
int cnt = 0;
for(int j=0; j<fatCnt; j++)
{
if(i & (1 << j))
{
cnt++;
tmp *= factor[j][0];
}
}
if(cnt & 1)//这里是欧拉函数的运用,奇数个就加上,偶数减去
ans += b/tmp;
else
ans -= b/tmp;
}
return b - ans;
}
int main()
{
//freopen("in.txt","r",stdin);
int t,a,b,c,d,k;
getPrime();
getEuler();
cin >> t;
for(int tt = 1; tt<=t; tt++)
{
cin >> a >> b >> c >> d >> k;
printf("Case %d: ",tt);
if(k == 0)
{
printf("0\n");
continue;
}
a = b / k;
b = d / k;
if(a < b)
swap(a,b);
LL ans = 0;
for(int i=1; i<=b; i++)
ans += euler[i];
for(int i=b+1; i<=a; i++)
{
ans += cal(i,b);
// printf("i = %d , ans = %I64d\n",i,ans);
}
printf("%I64d\n",ans);
}
return 0;
}