题目链接:https://atcoder.jp/contests/abc158/tasks/abc158_f
题目大意
有$N$个机器人分布在数轴上不同的位置,初始为未激活状态,作为上帝,你可以手动激活任意数量的机器人,当第$i$个机器人被激活时,它会向前走$D_i$个单位长度然后自爆,并且坐标区间在$[X_i,~Di)$上的机器人也会被激活往前走,从而触发连锁激活。
当你选定一些机器人激活后,最后剩下的机器人按编号组成集合$S$,问一共有多少个不同的集合$S$?
分析
对于每一个机器人,无非有激活和未激活两种状态,因此,很容易就能想到可以用动态规划或者记忆化搜索来做。
但是每个机器人不仅仅只是影响它的下一个机器人,有可能一个都不影响,有可能影响一片,所以要计算每个机器人的影响范围。
先是直接影响范围,也就是这个机器人自身会激活的最远的机器人,可以用二分实现。
接着是间接影响范围,也就是这个机器人激活的机器人会激活的最远的机器人,可以使用线段树查询最值。
代码如下
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 /*-------------------Define Start-------------------*/ 5 typedef bool BL; // 布尔类型 6 typedef char SB; // 有符号1字节,8位 7 typedef unsigned char UB; // 无符号1字节,8位 8 typedef short SW; // 有符号短整型,16位 9 typedef unsigned short UW; // 无符号短整型,16位 10 typedef long SDW; // 有符号整型,32位 11 typedef unsigned long UDW; // 无符号整型,32位 12 typedef long long SLL; // 有符号长整型,64位 13 typedef unsigned long long ULL; // 无符号长整型,64位 14 typedef char CH; // 单个字符 15 typedef float R32; // 单精度浮点数 16 typedef double R64; // 双精度浮点数 17 18 #define Rep(i, n) for (register SDW i = 0; i < (n); ++i) 19 #define For(i, s, t) for (register SDW i = (s); i <= (t); ++i) 20 #define rFor(i, t, s) for (register SDW i = (t); i >= (s); --i) 21 #define foreach(i, c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) 22 #define ms0(a) memset(a,0,sizeof(a)) 23 #define msI(a) memset(a,0x7f,sizeof(a)) 24 #define LOWBIT(x) ((x)&(-x)) 25 26 #define MP make_pair 27 #define PB push_back 28 #define ft first 29 #define sd second 30 #define ALL(x) x.begin(),x.end() 31 32 #define pr(x) cout << #x << " = " << x << " " 33 #define prln(x) cout << #x << " = " << x << endl 34 35 #define lson l , mid , rt << 1 36 #define rson mid + 1 , r , rt << 1 | 1 37 38 const ULL mod = 998244353; //常用模数(可根据题目需要修改) 39 const ULL inf = 0x7fffffff; //用来表示无限大 40 const ULL infLL = 0x7fffffffffffffffLL; //用来表示无限大 41 const R64 EPS = 1e-8; 42 /*-------------------Define End-------------------*/ 43 44 struct Robot{ 45 SDW X, D; 46 SDW next; // 当激活了这个机器人,它所能连续激活的最远的机器人id的下一个id 47 48 inline BL operator< (const Robot& x) { return X < x.X; } 49 }; 50 51 istream& operator>> (istream& in, Robot &x) { 52 in >> x.X >> x.D; 53 return in; 54 } 55 56 const UDW maxN = 2e5 + 7; 57 SDW N; 58 Robot robots[maxN]; 59 SDW dp[maxN]; // dp[i]代表区间[i, N - 1] 有多少种激活方法 60 SDW ans; 61 62 void input(){ 63 cin >> N; 64 Rep(i, N) { 65 cin >> robots[i]; 66 } 67 robots[N].X = inf; //设置哨兵 68 robots[N].next = N + 1; 69 N++; 70 } 71 72 /*---------------线段树------------------*/ 73 SDW st[maxN << 2]; 74 75 inline void pushUp(SDW rt) { 76 st[rt] = max(st[rt << 1], st[rt << 1 | 1]); 77 } 78 79 inline void build(SDW l, SDW r, SDW rt) { 80 if(l >= r) { 81 st[rt] = robots[r - 1].next; 82 return; 83 } 84 SDW mid = (l + r) >> 1; 85 build(lson); 86 build(rson); 87 pushUp(rt); 88 } 89 90 // 单点更新 91 inline void update(SDW x, SDW y, SDW l, SDW r, SDW rt) { 92 if(l >= r) { 93 st[rt] = y; 94 return; 95 } 96 SDW mid = (l + r) >> 1; 97 if(x <= mid) update(x, y, lson); 98 else update(x, y, rson); 99 pushUp(rt); 100 } 101 102 // 区间查询 103 inline SDW query(SDW L, SDW R, SDW l, SDW r, SDW rt) { 104 if(L <= l && r <= R) return st[rt]; 105 SDW ret = 0; 106 SDW mid = (l + r) >> 1; 107 108 if(L <= mid) ret = max(ret, query(L, R, lson)); 109 if(R > mid) ret = max(ret, query(L, R, rson)); 110 return ret; 111 } 112 /*---------------线段树------------------*/ 113 114 // 计算每个robot的next值 115 void getNext() { 116 // 先用二分计算机器人的直接next 117 rFor(i, N - 2, 0) { 118 SDW L = i + 1; 119 SDW R = N - 1; 120 121 while(L < R) { 122 SDW mid = (L + R) >> 1; 123 124 if(robots[mid].X > robots[i].X + robots[i].D - 1) { 125 R = mid; 126 } 127 else { 128 L = mid + 1; 129 } 130 } 131 132 robots[i].next = R; 133 } 134 135 build(1, N, 1); 136 137 // 再计算间接next并更新next值 138 rFor(i, N - 2, 0) { 139 //查找区间[i, robots[i].next - 1]上的机器人的最大的next 140 robots[i].next = query(i + 1, robots[i].next, 1, N, 1); // 线段树节点从1开始 141 update(i + 1, robots[i].next, 1, N, 1); 142 } 143 } 144 145 void solve(){ 146 sort(robots, robots + N); 147 getNext(); 148 149 dp[N - 1] = 1; 150 rFor(i, N - 2, 0) { 151 // 激活机器人x 152 dp[i] = (dp[i] + dp[robots[i].next]) % mod; 153 // 不激活机器人x 154 dp[i] = (dp[i] + dp[i + 1]) % mod; 155 } 156 157 ans = dp[0]; 158 } 159 160 void output(){ 161 cout << ans << endl; 162 } 163 164 int main() { 165 input(); 166 solve(); 167 output(); 168 return 0; 169 }