hdu 5317 RGCDQ(前缀和)

  题目链接:hdu 5317

  这题看数据量就知道需要先预处理,然后对每个询问都需要在 O(logn) 以下的复杂度求出,由数学规律可以推出 1 <= F(x) <= 7,所以对每组(L, R),只需要求出它们在 1~7 的范围内的数量,然后暴力求出 gcd 即可。因为符合递增,可以设一个结点 struct { v[8]; } 记录 1~7 的数量,结点间可以相加减,也就可以用前缀和的思想去做(其实我也是看了别人的题解才明白这种思想,一开始用二分不是超时就是 wa 了,不过我竟发现自己手写的二分比库函数 lower_bound 要快!而且至少快 7~8 倍以上!看来以后用二分都尽量自己手写好了 (ㄒoㄒ)~~ )

  先附上用前缀和的思想的代码,加入了输入输出挂:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 1000006;
 6 
 7 struct node {
 8     int v[8];
 9     node() {   memset(v,0,sizeof(v));   }
10     node operator + (const node &n2) const {
11         node add;
12         for(int i = 1; i <= 7; ++i)
13             add.v[i] = v[i] + n2.v[i];
14         return add;
15     }
16     node operator - (const node &n2) const {
17         node sub;
18         for(int i = 1; i <= 7; ++i)
19             sub.v[i] = v[i] - n2.v[i];
20         return sub;
21     }
22     node& operator += (const node &n2) {
23         *this = *this + n2;
24         return *this;
25     }
26     node& operator -= (const node &n2) {
27         return *this = *this - n2;
28     }
29 };
30 
31 int num[N];
32 node _count[N];
33 inline void init(int n = N - 3) {
34     for(int i = 2; i <= n; ++i)
35         if(!num[i])
36         for(int j = i; j <= n; j += i)   ++num[j];
37     for(int i = 2; i <= n; ++i) {
38         node tmp;
39         ++tmp.v[num[i]];
40         _count[i] = _count[i - 1] + tmp;
41     }
42 }
43 
44 inline int gcd(int a, int b) {
45     return b == 0 ? a: gcd(b, a % b);
46 }
47 
48 #include<cctype>
49 template <typename T>
50 inline void read(T &x) {
51     x = 0;
52     char ch = getchar();
53     bool flag = 0;
54     while(!isdigit(ch) && ch != '-')   ch = getchar();
55     if(ch == '-') {
56         flag = 1;
57         ch = getchar();
58     }
59     while(isdigit(ch)) {
60         x = x * 10 + (ch - '0');
61         ch = getchar();
62     }
63     if(flag)    x = -x;
64 }
65 
66 template <typename T>
67 inline void write(const T &x) {
68     if(x < 10)   putchar(char(x + '0'));
69     else    write(x / 10);
70 }
71 
72 int main() {
73     int t,L,R;
74     init();
75     read(t);
76     while(t--) {
77         read(L);    read(R);
78         node p = _count[R] - _count[L - 1];
79         int ans = 0;
80         for(int i = 1; i <= 7; ++i) {
81             if(!p.v[i])   continue;
82             --p.v[i];
83             for(int j = i; j <= 7; ++j)
84                 if(p.v[j])    ans = max(ans, gcd(i,j));
85             ++p.v[i];
86         }
87         write(ans);
88         puts("");
89     }
90     return 0;
91 }
View Code

  说到前缀和,就可以联想起高效动态维护前缀和的树状数组。没错,只要能求前缀和的数据结构,都能用树状数组去维护,它的适用范围不只是简单的 int,long long 或者 一维数组(二维树状数组去维护)等等。因此我定义成模板类:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cctype>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N = 1000006;
 7 
 8 struct node {
 9     int v[8];
10     void clear()  {   memset(v,0,sizeof(v));   }
11     node()  {   clear();   }
12     node operator + (const node &n2) const {
13         node add;
14         for(int i = 1; i <= 7; ++i)
15             add.v[i] = v[i] + n2.v[i];
16         return add;
17     }
18     node operator - (const node &n2) const {
19         node sub;
20         for(int i = 1; i <= 7; ++i)
21             sub.v[i] = v[i] - n2.v[i];
22         return sub;
23     }
24 };
25 
26 #define  lowbit(x)  ((x)&-(x))
27 template <typename T>
28 struct tree {
29     T c[N];
30     int maxn;
31     void clear() {      // 或者直接 memset(c, 0, sizeof(c)) 也可以;
32         for(int i = 0; i <= maxn; ++i)
33             c[i].clear();
34     }
35     tree(int maxn = N - 3): maxn(maxn)  {   clear();   }
36     T sum(int x) const {
37         T res;
38         while(x) {
39             res = res + c[x];
40             x -= lowbit(x);
41         }
42         return res;
43     }
44     void add(int x, T d) {
45         while(x <= maxn) {
46             c[x] = c[x] + d;
47             x += lowbit(x);
48         }
49     }
50 };
51 
52 tree<node> tr;
53 
54 int num[N];
55 void init(int n = N - 3) {
56     for(int i = 2; i <= n; ++i)
57         if(!num[i])
58         for(int j = i; j <= n; j += i)  ++num[j];
59     for(int i = 2; i <= n; ++i) {
60         node tmp;
61         ++tmp.v[num[i]];
62         tr.add(i, tmp);
63     }
64 }
65 
66 inline int gcd(int a, int b) {
67     return b == 0 ? a: gcd(b, a % b);
68 }
69 
70 int main() {
71     int t,L,R;
72     init();
73     scanf("%d",&t);
74     while(t--) {
75         scanf("%d %d",&L,&R);
76         node p = tr.sum(R) - tr.sum(L - 1);
77         int ans = 0;
78         for(int i = 1; i <= 7; ++i) {
79             if(!p.v[i])   continue;
80             --p.v[i];
81             for(int j = i; j <= 7; ++j)
82                 if(p.v[j])   ans = max(ans, gcd(i, j));
83             ++p.v[i];
84         }
85         printf("%d\n",ans);
86     }
87     return 0;
88 }
View Code

 

posted @ 2015-07-31 12:01  Newdawn_ALM  阅读(132)  评论(0编辑  收藏  举报