博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu 4351 Digital root
阅读量:6429 次
发布时间:2019-06-23

本文共 4531 字,大约阅读时间需要 15 分钟。

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

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

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

代码如下:

View Code
1 #include 
2 #include
3 #include
4 #include
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/archive/2012/10/22/hdu_4351_Lyon.html

你可能感兴趣的文章
VULKAN学习笔记-inter教学四篇
查看>>
spring boot 环境搭建
查看>>
rem 适配
查看>>
Java并发编程:volatile关键字解析
查看>>
UvaLive4255 Guess
查看>>
for in
查看>>
LeetCode 341: Flatten Nested List Iterator
查看>>
linux-菜鸟新手命令(1)
查看>>
CSS3学习之linear-gradient(线性渐变)
查看>>
滑动最小值
查看>>
guruguru
查看>>
[转]addEventListener() 方法,事件监听
查看>>
javacript的一些基本
查看>>
关于H5页面在iPhoneX适配(转)
查看>>
2012蓝桥杯【初赛试题】身份证
查看>>
C++中的类模板
查看>>
2013蓝桥杯 【初赛试题】 马虎的算式
查看>>
杭电 FatMouse' Trade
查看>>
mac下如何用Xcode从svn服务器Check Out出项目源代码
查看>>
原生js实现放大镜
查看>>