hdu 1695 GCD 容斥原理 ural 1091

以下转自于:

http://blog.sina.com.cn/s/blog_59e67e2c0100a84o.html

题目意思不难已知给定k,x,y求 1<=a<=x 1<=b<=y 中满足 gcd(a,b)=k 的(a,b)对数。(注意数对是无序的)。 1<=x,y<=10w, 0<=k<=10w

 

 题目有比较恶心的一点,数据有k==0的,这时显然答案是0,没有2个数的gcd为0。

 首先,gcd是没啥用的。因为约掉gcd后两个数互质。于是我们可以让x/=k y/=k并且假设 x<=y

 然后题目变成了 2个数分别在区间[1..x]和[1..y]中的互质数有多少对。

 大体思路:

     枚举[1..y]中每个数i 判断[1..min(x,i)]中有多少数与i互质,统计个数。(注意,枚举的是比较大的区间[1..y])。

     显然如果i是质数,则[1..min(x,i)]中与i互质的个数是全体的个数或者i-1个。(取决于x和i的大小)。

     当i不是质数时,i分解质因数后,质因数的次数不影响结果。我们看另外那个区间有多少个和i不互质(减一下就好了),于是我们只要看另外那个区间中有多少个数是i质因数的倍数就好了。

     区间[1..w]中 p的倍数 显然有 w/p个。

     我们枚举i的质因数利用容斥原理:

          看另外那个区间有多少个数与i不互质。

          容斥原理的具体如下:

          区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的成绩的倍数个数)-(区间中i的每4个质因数的乘积)+...

          于是问题变成了统计每个数的不同质因数的个数而忽略次数。这个可以用筛法。具体做法如下:

          对每个数保存一个真质因数的列表。初始每个列表的长度为0。然后从2开始,分别检查每个数的列表长度,如果列表长度不为0,则这个数是合数,跳过;如果这个长度为0,则我们找到了一个质数,同时再把这个数的倍数(不包含本身)的列表里加入这个数。

           这样筛一次下来,我们保存了每个数的真质因数列表,问题得到解决,还要注意结果用要用__int64。

 

/*
* hdu1695.c
*
* Created on: 2011-10-3
* Author: bjfuwangzhu
*/

#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define nmax 100010
int prime[nmax], phi[nmax], pfactor[nmax], cpfactor[nmax];
int plen, pflen;
void init() {
int i, j;
memset(phi, 0, sizeof(phi));
phi[0] = 0, phi[1] = 1;
for (i = 2, plen = 0; i < nmax; i++) {
if (!phi[i]) {
phi[i] = i - 1;
prime[plen++] = i;
}
for (j = 0; (j < plen) && (i * prime[j] < nmax); j++) {
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
} else {
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
}
void getpFactor(int n) {
int i, te;
te = (int) sqrt(n * 1.0);
for (i = 0, pflen = 0; (i < plen) && (prime[i] <= te); i++) {
if (n % prime[i] == 0) {
cpfactor[pflen] = 0;
while (n % prime[i] == 0) {
n /= prime[i];
cpfactor[pflen]++;
}
pfactor[pflen++] = prime[i];
}
}
if (n > 1) {
cpfactor[pflen] = 1;
pfactor[pflen++] = n;
}
}
LL dfs(int n, int start) {
int i;
LL res;
for (i = start, res = 0; i < pflen; i++) {
res += n / pfactor[i] - dfs(n / pfactor[i], i + 1);
}
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int t, i, j, a, b, c, d, k;
LL res;
init();
scanf("%d", &t);
for (i = 1; i <= t; i++) {
scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
b /= a, d /= c;
if (k == 0 || k > b || k > d) {
res = 0;
} else {
b /= k, d /= k;
if (b > d) {
b ^= d, d ^= b, b ^= d;
}
for (j = 1, res = 0; j <= b; j++) {
res += phi[j];
}
for (j = b + 1; j <= d; j++) {
getpFactor(j);
res += b - dfs(b, 0);
}
}
printf("Case %d: %I64d\n", i, res);
}
return 0;
}


ural 1091. Tmutarakan Exams

http://acm.timus.ru/problem.aspx?space=1&num=1091

/*
* timus1091.c
*
* Created on: 2011-10-6
* Author: bjfuwangzhu
*/

#include<stdio.h>
#define pnum 15
#define nmax 10000
int prime[pnum] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 };
int mark;
int solve(int n, int k, int m) {
int te, i, res;
te = n / m;
if (k > te) {
return 0;
}
if (k > te / 2) {
k = te - k;
}
for (i = 0, res = 1; i < k; i++) {
res = res * (te - i) / (i + 1);
if (res >= nmax) {
return -1;
}
}
return res;
}
int dfs(int start, int s, int k) {
int i, res, temp;
for (i = start, res = 0; (i < pnum) && (prime[i] <= s); i++) {
temp = solve(s, k, prime[i]);
if (temp == -1) {
mark = 1;
return 0;
} else {
res += temp - dfs(i + 1, s / prime[i], k);
}
if (res >= nmax) {
mark = 1;
return 0;
}
}
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int k, s, res;
while (~scanf("%d %d", &k, &s)) {
mark = 0;
res = dfs(0, s, k);
if (mark) {
res = nmax;
}
printf("%d\n", res);
}
return 0;
}

你可能感兴趣的:(HDU)