hdu 1695 一道综合性很强的数论题

这题想了好久,代码也打了好久。挺不错的一道数论题。

题目是要求两个集合(1...b, 1...d)中有多少对数的最大公约数为K,此问题等价于求两个集合(1...b/k,1...d/k)中有多少对数互质。

不妨设b<d,则题目可以分为两部分求解,即:

①(1...b)与(1...b)中有多少对数互质

②(1...b)与(b+1...d)中有多少对数互质

问题1就是欧拉函数的应用,就不详细说了。

对于问题2,直接求不好求,我们倒过来想。对于(b+1...d)中的每一个y,要想知道(1...b)中有多少数与它互质,我们只需要知道多少个数与它不互质即可。而两个数不互质就意味着它们有公因子。对于每一个y的因子f,都能确定地知道(1...b)中有多少个数含有因子f,用容斥原理算一下,就能知道(1...b)中有多少个数与y互质了。枚举一下y即可解决问题②了。

/*
* hdu1695/win.cpp
* Created on: 2011-12-11
* Author : ben
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std;
const int MAXN = 100005;
const int MAXSQRN = 500;
typedef long long I64;
int phi[MAXN], facts[MAXSQRN], prime[MAXSQRN], primenum;

void initprime() {
primenum = 3;
prime[0] = 2;
prime[1] = 3;
prime[2] = 5;
for (int i = 6; i < MAXSQRN; i++) {
int j = 2;
for (; j < i; j++) {
if (i % j == 0) {
break;
}
}
if (j == i) {
prime[primenum++] = i;
}
}
}

inline int getFacts(int y) {
int I = 0;
for (int i = 0; i < primenum; i++) {
if (y <= 1) {
break;
}
if (y % prime[i] == 0) {
facts[I++] = prime[i];
while (y % prime[i] == 0) {
y /= prime[i];
}
}
}
if(y > 1) {
facts[I++] = y;
}
return I;
}

void initphi() {
int i, j;
for (i = 1; i <= MAXN; i++) {
phi[i] = i;
}
for (i = 2; i <= MAXN; i += 2) {
phi[i] /= 2;
}
for (i = 3; i <= MAXN; i += 2) {
if (phi[i] == i) {
for (j = i; j <= MAXN; j += i) {
phi[j] = phi[j] / i * (i - 1);
}
}
}
}

I64 thesame(int end) {
I64 ret = 1;
for (int i = end; i > 1; i--) {
ret += phi[i];
}
return ret;
}

I64 dfs(int n, int start, int I) {
I64 res = 0;
int i;
for (i = start; i < I; i++) {
res += n / facts[i] - dfs(n / facts[i], i + 1, I);
}
return res;
}

I64 thediff(int b, int d) {
I64 ret = 0;
for (int y = b + 1; y <= d; y++) {
int I = getFacts(y);
//容斥原理
ret += b - dfs(b, 0, I);
}
return ret;
}

int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int T, b, d, k, t;
I64 ans;
initphi();
initprime();
scanf("%d", &T);
for (t = 1; t <= T; t++) {
printf("Case %d: ", t);
scanf(" 1 %d 1 %d %d", &b, &d, &k);
if (b < k || d < k || k == 0) {
puts("0");
continue;
}
b /= k;
d /= k;
if (b > d) {
b = b ^ d;
d = b ^ d;
b = b ^ d;
}
ans = thesame(b);
ans += thediff(b, d);
printf("%I64d\n", ans);
}
return 0;
}



你可能感兴趣的:(HDU)