蓝桥杯——试题 算法训练 Number Challenge
试题 算法训练 Number Challenge
资源限制
时间限制:3.0s 内存限制:512.0MB
问题描述
定义d(n)为n的约数个数。现在,你有三个数a,b,c。你的任务是计算下面式子modulo 1073741824 (2^30)的值。
输入格式
三个正整数a,b,c。
输出格式
一个数,即上面式子modulo 1073741824 (2^30)的值。
样例输入
2 2 2
样例输出
20
数据规模和约定
a, b , c (1 ≤ a, b, c ≤ 2000)
public class Main {
// 转自: https://blog.csdn.net/a1439775520
static int MAX = 2005;
static int MOD = 1 << 30;
static int[][] gd = new int[MAX][MAX];
static int[] p = new int[MAX];
static int[] mob = new int[MAX];
/**
* 下标代表这个数,如果下标对应的数组中的值为true,则表示该数不是素数,反之,则是素数
*/
static boolean[] noprime = new boolean[MAX];
static void Mobius() {
int pnum = 0;
// 1的约数只有一个数:1
mob[1] = 1;
// 循环中的i变量代表了此时要判断的这个数
for (int i = 2; i < MAX; i++) {
// 判断是否为素数
if (!noprime[i]) {
// 是素数
// p数组用于存储1~2004之间的所有素数
p[pnum++] = i;
// mob将所有为素数的数在数组中设置为-1
mob[i] = -1;
}
// 找此时i的倍数,只要是i的倍数就一定不是素数,将其下标对应的noprime数组中的值修改为true,表明这个数不是素数
for (int j = 0; j < pnum && i * p[j] < MAX; j++) {
// j < pnum 这个限制条件的作用:此时已经确定pnum - 1个素数了,pnum后面的还没有确定,其默认值都是0,就没必要访问了
// i * p[j] < MAX 加上这个限制条件是为了不让noprime数组的下标越界
noprime[i * p[j]] = true;
// 判断此时的i是否能整除此时的p[j]————》(i是p[j]的倍数就跳出循环,不再往后继续了)
if (i % p[j] == 0) {
mob[i * p[j]] = 0;
break;
}
mob[i * p[j]] = -mob[i];
}
}
}
static int Gcd(int a, int b) {
if (b == 0) {
return a;
}
if (gd[a][b] == 1) {
return gd[a][b];
}
return gd[a][b] = Gcd(b, a % b);
}
static long cal(int d, int x) {
long ans = 0;
for (int i = 1; i <= d; i++) {
if (Gcd(i, x) == 1) {
ans += (long) (d / i);
}
}
return ans;
}
public static void main(String[] args) {
Mobius();
int a, b, c;
long ans = 0L;
Scanner sc = new Scanner(System.in);
a = sc.nextInt();
b = sc.nextInt();
c = sc.nextInt();
sc.close();
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= Math.min(b, c); j++) {
if (Gcd(i, j) == 1) {
ans = (ans % MOD + (long) (a / i) * mob[j] * cal(b / j, i) * cal(c / j, i) % MOD) % MOD;
}
}
}
System.out.println(ans);
}
}