Maximum number, GCD condition (codechef March Challenge 2014)

题目 : http://acm.bnu.edu.cn/v3/problem_show.php?pid=40489

最近做到的一道蛮有意思的题目(codechef现在的题目确实很赞了)

题意 :中文题面 (cc的一大好处就是有中文翻译,嘿嘿)

区间Max = max{a_i|gcd(a_i, g) > 1 && x <= i <= y}

做法 : 一开始我是用分块做的,复杂的O(m * sqrt(n) * C) C 是所含不同素数的个数, C大概最大只有6或7吧

然后裸裸的T了,换了一个姿势:用线段树或者RMQ把查询从sqrt(n) -> log(n), 这里最初的想法就是直接对于每个素数开一个线段树,但是这样预处理空间和时间都过不了

,但是考虑的其实n个数都分解一下只有C*n个数,那么的话我们可以用动态开线段树的方法,当然这个我不会- - !,还有一种比较好的实现方式是对于每个素数都建立一段段的RMQ,额,, 具体就是比如 a[] : 2, 3, 4, 6 那么我建立一个RMQ为 :2 4 6 3 6,前三个是2的倍数,后两个是3的倍数,,并通过一些其他辅助操作可以使得复杂度降为log(n)。

分块做法(TLE) :

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <vector>
 5 
 6 using namespace std;
 7 inline int gcd(int a, int b) {return !b ? a : gcd(b, a % b);}
 8 const int MAXN = 100005;
 9 int check[MAXN] = {0};
10 const int M = 320;
11 vector<int> prime[MAXN];
12 int ptot = 0;
13 int n, m;
14 int blocks[1<<9][10005];
15 int a[MAXN];
16 void init(int N) {
17     for (int i = 2; i <= N; i++) {
18         if (!check[i]) {
19             for (int j = 1; j * i <= N; j++) {
20                 prime[j * i].push_back(i);
21                 check[i * j] = 1;
22             }
23             check[i] = ++ ptot;
24         }
25     }
26 }
27 vector<int> G[MAXN];
28 int query(int x, int y, int e) {
29     return upper_bound(G[e].begin(), G[e].end(), y) - lower_bound(G[e].begin(), G[e].end(), x);
30 }
31 
32 int main() {
33     init(100000);
34     scanf("%d%d", &n, &m);
35     for (int i = 1; i <= n; i++) {
36         scanf("%d", &a[i]);
37         int e = i / M;
38         for (int j = 0; j < prime[a[i]].size(); j++) {
39             int v = prime[a[i]][j];
40             blocks[e][check[v]] = max(blocks[e][check[v]], a[i]);
41         }
42         G[a[i]].push_back(i);
43     }
44     while (m --) {
45         int g, x, y;
46         scanf("%d%d%d", &g, &x, &y);
47         int l = x / M, r = y / M, Max = -1;
48         if (l == r) {
49             for (int i = x; i <= y; i++) {
50                 if (gcd(g, a[i]) > 1) Max = max(Max, a[i]);
51             }
52         }else {
53             for (int i = x; i < (l+1) * M; i++) {
54                 if (gcd(g, a[i]) > 1) Max = max(Max, a[i]);
55             }
56             for (int i = r * M; i <= y; i++) {
57                 if (gcd(g, a[i]) > 1) Max = max(Max, a[i]);
58             }
59             for (int i = 0; i < prime[g].size(); i++) {
60                 int v = prime[g][i];
61                 for (int j = l + 1; j <= r - 1; j++) {
62                     if (blocks[j][v] > 0)Max = max(Max, blocks[j][v]);
63                 }
64             }
65         }
66         if (Max == -1) printf("-1 -1\n");
67         else {
68             printf("%d %d\n", Max, query(x, y, Max));
69         }
70     }
71     return 0;
72 }
View Code

RMQ做法:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <vector>
 5 
 6 using namespace std;
 7 const int MAXN = 100005;
 8 struct RMQ {
 9     int a[MAXN * 7][20];
10     int log2[MAXN * 7];
11     void init(int A[], int N) {
12         for (int i = 0; i < MAXN * 7; i++) log2[i] = (i == 0 ? -1 : log2[i >> 1] + 1);
13         for (int i = 1; i <= N; i++) a[i][0] = A[i];
14         for (int j = 1; (1 << j) <= N; j++) {
15             for (int i = 1; i + (1<<j) - 1 <= N; i++) {
16                 a[i][j] = max(a[i][j-1], a[i + (1<<(j-1))][j - 1]);
17             }
18         }
19     }
20     int rmq(int L, int R) {
21         if (R < L) return 0;
22         int k = log2[R - L + 1];
23         return max(a[L][k], a[R-(1<<k)+1][k]);
24     }
25 }AC;
26 vector<int> prime[MAXN];
27 int check[MAXN] = {0}, ptot = 0;
28 void init(int N) {
29     for (int i = 2; i <= N; i++) {
30         if (!check[i]) {
31             for (int j = 1; j * i <= N; j++) {
32                 prime[j * i].push_back(i);
33                 check[i * j] = 1;
34             }
35             check[i] = ++ ptot;
36         }
37     }
38 }
39 vector<int> G[MAXN];
40 int query(int x, int y, int e) {
41     return upper_bound(G[e].begin(), G[e].end(), y) - lower_bound(G[e].begin(), G[e].end(), x);
42 }
43 int n, m;
44 int b[MAXN * 7];
45 int a[MAXN];
46 int pre[MAXN];
47 vector<int> gao[MAXN];
48 
49 int main() {
50     init(100000);
51     scanf("%d%d", &n, &m);
52     for (int i = 1; i <= n; i++) {
53         scanf("%d", &a[i]);
54         for (int j = 0; j < prime[a[i]].size(); j++) {
55             int v = check[prime[a[i]][j]];
56             gao[v].push_back(i);
57         }
58         G[a[i]].push_back(i);
59     }
60     int tot = 0;
61     for (int i = 1; i <= ptot; i++) {
62         if (gao[i].size() == 0) continue;
63         pre[i] = tot;
64         for (int j = 0; j < gao[i].size(); j++) {
65             b[++ tot] = a[gao[i][j]];
66         }
67     }
68     AC.init(b, tot);
69     while (m--) {
70         int g, x, y, Max = -1;
71         scanf("%d%d%d", &g, &x, &y);
72         for (int i = 0; i < prime[g].size(); i++) {
73             int v = check[prime[g][i]];
74             int r = upper_bound(gao[v].begin(), gao[v].end(), y) - gao[v].begin() + pre[v] + 1;
75             int l = lower_bound(gao[v].begin(), gao[v].end(), x) - gao[v].begin() + pre[v] + 1;
76             r --;
77             if (r >= l)Max = max(Max, AC.rmq(l, r));
78         }
79         if (Max == -1) {
80             printf("-1 -1\n");
81         }else {
82             printf("%d %d\n", Max, query(x, y, Max));
83         }
84     }
85     return 0;
86 }
View Code

 

posted @ 2014-10-16 21:59  danceonly、  阅读(275)  评论(0编辑  收藏  举报