Description
Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
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.
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 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.
Output
For each test case, print the number of choices. Use the format in the example.
Sample Input
2
1 3 1 5 1
1 11014 1 14409 9
Sample Output
Case 1: 9
Case 2: 736427
求gcd(x,y)==k的有几对1<=x<=n,1<=y<=m且x和y换位算相同。
先同时除于k,然后对于两个范围都有的用欧拉函数统计,超过的用容斥原理。
#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define ff first
#define ss second
#define mp(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,LL>
#define inone(x) scanf("%d", &x);
#define intwo(x,y) scanf("%d%d", &x, &y);
using namespace std;
typedef unsigned long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-4;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int T, n, m, q, cas = 0;
int phi[N], f[N], p[N], g[N], t = 0;
void init()
{
phi[1] = f[1] = 1; g[1] = 1;
rep(i, 2, N - 1)
{
if (!f[i]) p[t++] = i, phi[i] = i - 1, g[i] = -1;
for (int j = 0, k; j < t&&p[j] * i < N; j++)
{
f[k = p[j] * i] = 1;
g[k] = g[i] * -1;
phi[k] = phi[i] * (p[j] - 1);
if (i%p[j] == 0)
{
phi[k] = phi[i] * p[j];
g[k] = 0; break;
}
}
}
}
int main()
{
init(); inone(T);
while (T--)
{
scanf("%d%d%d%d%d", &n, &n, &m, &m, &q);
if (!q) { printf("Case %d: 0\n", ++cas); continue; }
n /= q; m /= q; if (n < m) swap(n, m);
LL ans = 0; rep(i, 1, m) ans += phi[i];
rep(i, m + 1, n)
{
for (int j = 1; j * j <= i; j++)
{
if (i % j) continue;
ans += m / (i / j) * g[i / j];
if (j*j == i) continue;
ans += m / j * g[j];
}
}
printf("Case %d: %lld\n", ++cas, ans);
}
return 0;
}
才发现,容斥原理其实和莫比乌斯反演是互通的,而本题可以作为莫比乌斯反演的模板题。
#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define ff first
#define ss second
#define mp(i,j) make_pair(i,j)
#define pb push_back
#define pii pair<int,LL>
#define inone(x) scanf("%d", &x);
#define intwo(x,y) scanf("%d%d", &x, &y);
using namespace std;
typedef unsigned long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int T, n, m, k, cas = 0;
int f[N], p[N], u[N], g[N], phi[N], t = 0;
LL s[N];
void init()
{
g[1] = phi[1] = f[1] = u[1] = 1; g[0] = s[1] = 0;
rep(i, 2, N - 1)
{
if (!f[i]) p[t++] = i, u[i] = -1, phi[i] = i - 1;
for (int j = 0, k; j < t && p[j] * i < N; j++)
{
f[k = i*p[j]] = 1; u[k] = -u[i];
phi[k] = phi[i] * (p[j] - 1);
if (i % p[j]) continue;
phi[k] = phi[i] * p[j]; u[k] = 0; break;
}
s[i] = s[i - 1] + phi[i];
g[i] = g[i - 1] + u[i];
}
}
int main()
{
init();
inone(T);
while (T--)
{
scanf("%d%d%d%d%d", &n, &n, &m, &m, &k);
LL ans1 = 0, ans2 = 0;
if (k)
{
n /= k; m /= k;
if (n > m) swap(n, m);
for (int i = 1, ii; i <= n; i = ii + 1)
{
ii = min(n / (n / i), m / (m / i));
ans1 += 1LL * (g[ii] - g[i - 1]) * (n / i) * (m / i);
}
ans2 = s[n];
}
printf("Case %d: %lld\n", ++cas, ans1 - ans2);
}
return 0;
}