hdu 4351 Digital root

http://acm.hdu.edu.cn/showproblem.php?pid=4351

  这题是一道稍微复杂的区间合并线段树,因为没有query,可以写成RMQ来降低query的复杂度。

  题意不难理解,先解释一下所谓的数字的根是指一个数的各位数字和的各位数字和的各位数字和的各位数字和。。。。直到数只剩一位。数字根有一个性质,就是它如果是非0,最后必然是非0的数;如果这个数模9余d,d!=0,d就是数字根,d==0,数字根就是9。知道性质以后,题目给出一列数,要求求出给定的一个区间里所有子序列的和的数字根中最大的5个数字根,不包括重复的。这个题意可以直接由下面的hint看出。

  解决这个问题需要对一个区间的子序列分类,让其可以进行区间合并的操作。例如,我在这题里面,将子序列分为不连接到左右两个端点的、连接到左(右)端点的,以及同时连接到两个端点(也就是整段区间)。这样,分别对它们操作,很容易就可以想到如何对任意给定区间进行合并,只是合并的操作相对繁琐罢了。如果像我这样做,区间中还得判断是否有0,以及是否全是0,这两种特殊情况。

代码如下:

View Code
  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 #define lson l, m, rt << 1
  9 #define rson m + 1, r, rt << 1 | 1
 10 
 11 const int maxn = 1E5 + 5;
 12 struct Seg {
 13     bool left[9], right[9], mid[9];
 14     bool onlyZero, zero;
 15     int whole;
 16 } seg[maxn << 2];
 17 
 18 Seg up(Seg left, Seg right) {
 19     Seg ret;
 20 
 21     ret.zero = left.zero | right.zero;
 22     ret.onlyZero = left.onlyZero & right.onlyZero;
 23     ret.whole = (left.whole + right.whole) % 9;
 24     for (int i = 0; i < 9; i++) {
 25         ret.left[i] = left.left[i];
 26         ret.right[i] = right.right[i];
 27         ret.mid[i] = left.mid[i] | right.mid[i] | left.right[i] | right.left[i];
 28     }
 29     if (!left.onlyZero) ret.left[left.whole] = true;
 30     if (!right.onlyZero) ret.right[right.whole] = true;
 31     for (int i = 0; i < 9; i++) {
 32         int l = (left.whole + i) % 9, r = (right.whole + i) % 9;
 33 
 34         if (!left.onlyZero) ret.left[l] |= right.left[i];
 35         if (!right.onlyZero) ret.right[r] |= left.right[i];
 36         for (int j = 0; j < 9; j++) {
 37             ret.mid[(i + j) % 9] |= (right.left[i] & left.right[j]);
 38         }
 39     }
 40 
 41     return ret;
 42 }
 43 
 44 void build(int l, int r, int rt) {
 45     if (l == r) {
 46         memset(&seg[rt], 0, sizeof(Seg));
 47         scanf("%d", &seg[rt].whole);
 48         seg[rt].zero = seg[rt].onlyZero = !seg[rt].whole;
 49         seg[rt].whole %= 9;
 50         return ;
 51     }
 52     int m = (l + r) >> 1;
 53 
 54     build(lson);
 55     build(rson);
 56     seg[rt] = up(seg[rt << 1], seg[rt << 1 | 1]);
 57 }
 58 
 59 Seg query(int L, int R, int l, int r, int rt) {
 60     Seg ret;
 61 
 62     if (L <= l && r <= R) {
 63         return seg[rt];
 64     }
 65     int m = (l + r) >> 1;
 66 
 67     if (L <= m) {
 68         ret = query(L, R, lson);
 69         if (m < R) {
 70             ret = up(ret, query(L, R, rson));
 71         }
 72         return ret;
 73     }
 74     if (m < R) {
 75         return query(L, R, rson);
 76     }
 77 
 78     return ret;
 79 }
 80 
 81 int main() {
 82     freopen("in", "r", stdin);
 83     int T, n;
 84 
 85     scanf("%d", &T);
 86     for (int i = 1; i <= T; i++) {
 87         if (i != 1) puts("");
 88         scanf("%d", &n);
 89         build(1, n, 1);
 90 //        for (int j = 1; j < n << 2; j++) {
 91 //            printf("%d : %d\n", j, seg[j].whole);
 92 //            for (int k = 0; k < 9; k++) {
 93 //                printf("rest %d : %d %d %d\n", k, seg[j].left[k], seg[j].mid[k], seg[j].right[k]);
 94 //            }
 95 //            puts("~~");
 96 //        }
 97 //        puts("~~~~~~");
 98         printf("Case #%d:\n", i);
 99 
100         int m;
101 
102         scanf("%d", &m);
103         while (m--) {
104             int l, r;
105 
106             scanf("%d%d", &l, &r);
107 
108             Seg ans = query(l, r, 1, n, 1);
109             int cnt = 5;
110             bool pr = false;
111 
112             for (int t = 9; t >= 1; t--) {
113                 int ii = t % 9;
114 
115                 if (ans.left[ii] || ans.right[ii] || ans.mid[ii] || (ans.whole == ii && !ans.onlyZero)) {
116                     if (pr) {
117                         putchar(' ');
118                     }
119                     pr = true;
120                     printf("%d", t);
121                     cnt--;
122                 }
123                 if (cnt == 0) break;
124             }
125             if (cnt && ans.zero) {
126                     if (pr) {
127                         putchar(' ');
128                     }
129                     pr = true;
130                     putchar('0');
131                     cnt--;
132             }
133             while (cnt--) {
134                 if (pr) putchar(' ');
135                 pr = true;
136                 printf("-1");
137             }
138             puts("");
139         }
140     }
141 
142     return 0;
143 }

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_4351_Lyon.html