题意:给出一个长度为 n 的数列 { a[1] , a[2] , a[3] , ... , a[n] },以及 m 组询问 ( l[i] , r[i], k[i])。
求数列下标区间在 [ l[i] , r[i] ] 中有多少数在该区间中的出现次数与 k[i] 互质(最大公约数为1)。
输入描述:
第一行,两个正整数 n , m (1 ≤ n, m ≤ 50000)。 第二行,n 个正整数 a[i] (1 ≤ a[i] ≤ n)描述这个数列。 接下来 m 行,每行三个正整数 l[i] , r[i] , k[i] (1 ≤ l[i] ≤ r[i] ≤ n, 1 ≤ k[i] ≤ n),描述一次询问。
输出描述:
输出 m 行,即每次询问的答案。
分析:这道题要求的是在某个区间内有多少个数出现的次数与k[i]互质。
题目中提到的一个很关键的点是a[i]属于[1,n],可以根据这个构建一个不算大的数组来记录a[i]在[left,right]中出现的次数,再次遍历这个数组,即可求在这个区间中与相应的k互质的次数有多少个。
代码:
package CodeM;
import java.util.Scanner;
public class RelativelyPrime_2017Aans {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] a = new int[n + 1];
int maxid = -1;
for (int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
maxid = maxid > a[i] ? maxid : a[i];
}
for (int i = 1; i <= m; i++) {
int[] vis = new int[maxid + 1];
int l = sc.nextInt();
int r = sc.nextInt();
int k = sc.nextInt();
for (int j = l; j <= r; j++) {
vis[a[j]] += 1;
}
int res = 0;
for (int p = 0; p < vis.length; p++) {
if (vis[p] == 0) continue;
if (gcd(vis[p], k) == 1) res += 1;
}
System.out.println(res);
}
}
private static int gcd(int a, int b) {
while (b > 0) {
int t = a % b;
a = b;
b = t;
}
return a;
}
}
还有一个解法是用一个二维数组times将每个数在当前位置为止出现的次数,在求[left,right]该数出现的次数时,就可以直接利用times[right]-times[left-1]求得。
import java.util.HashMap;
import java.util.Scanner;
public class RelativelyPrime_2017A {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] a = new int[n + 1];
HashMap<Integer, Integer> all = new HashMap<>();
int k = 0;
for (int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
if (!all.containsKey(a[i])) {
all.put(a[i], k++);
}
}
//use times to record every a[i]'s times
int[][] times = new int[all.size()][n + 1];
for (int j = 1; j <= n; j++) {
int key = all.get(a[j]);
times[key][j] = times[key][j - 1] + 1;
for (int i = 0; i < times.length; i++) {
times[i][j] = Math.max(times[i][j], times[i][j - 1]);
}
}
for (int i = 0; i < m; i++) {
int l = sc.nextInt();
int r = sc.nextInt();
k = sc.nextInt();
//ArrayList<Integer> exist = new ArrayList<>();
long res = 0;
for (int x = 0; x < times.length; x++) {
int time = times[x][r] - times[x][l - 1];
//System.out.println(l+"\t"+r+"\t"+time);
if (time == 0)
continue;
if (gcd(k, time) == 1) {
// exist.add(time);
res += 1;
}
}
System.out.println(res);
}
}
private static int gcd(int a, int b) {
while (b > 0) {
int t = a % b;
a = b;
b = t;
}
return a;
}
}