zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    MongoDB 释放磁盘空间 db.runCommand({repairDatabase: 1 })
    RK 调试笔记
    RK Android7.1 拨号
    RK Android7.1 移植gt9271 TP偏移
    RK Android7.1 定制化 itvbox 盒子Launcher
    RK Android7.1 双屏显示旋转方向
    RK Android7.1 设置 内存条作假
    RK Android7.1 设置 蓝牙 已断开连接
    RK Android7.1 进入Camera2 亮度会增加
    RK 3128 调触摸屏 TP GT9XX
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_4351_Lyon.html
Copyright © 2011-2022 走看看