constint M = 10000; bool Vis[M + 1]; int F[M + 1];
voidupdate(int &x, int y){ if(y < x) x = y; }
intmain(){ int n; cin >> n; for (int i = 0; i <= M; i++) { F[i] = INT_MAX; } ① int r = 0; while (②) { r++; int x = 0; for (int i = 1; i <= M; i++) if(③) x = i; Vis[x] = 1; for (int i = 1; i <= M; i++) { if(④) { int t = F[i] + F[x]; if(i + x <= M) update(F[i + x], t); if(i != x) update(F[abs(i - x)], t); if(i % x == 0) update(F[i / x], t); if(x % i == 0) update(F[x / i], t); } } } cout << F[n] << endl; return0; }
①处应填( ) A. F[4] = 0 B. F[1] = 4 C. F[1] = 2 D. F[4] = 1
解析:
DP 的初始值,肯定是 1 个四就是四,选 D
②处应填( ) A. !Vis[n] B. r < n C. F[M] == INT_MAX D. F[n] == INT_MAX
解析:
只要我们要找到数没有算出来,就不能结束,也就是 A
③处应填( ) A. F[i] == r B. !Vis[i] && F[i] == r C. F[i] < F[x] D. !Vis[i] && F[i] < F[x]
解析:
x 是我们要找到的目前花费最少的点,这样才可以让后面花费少,类似于 Dijkstra ,所以选 D
④处应填( ) A. F[i] < F[x] B. F[i]<=r C. Vis[i] D. i <= x
解析:
两个数转移到新的数,只有当这两个数都是最优的时候,才能保证本次转移不会白转移(指其中一个数再更新本次转移作废)选 C 。
voidST_init(){ b = (int)(ceil(log2(t) / 2)); c = t / b; Log2[1] = 0; for (int i = 2; i <= c; i++) Log2[i] = Log2[i >> 1] + 1; for (int i = 0; i < c; i++) { Min[0][i] = A[i * b]; for (int j = 1; j < b; j++) Min[0][i] = min(Min[0][i], A[i * b + j]); } for (int i = 1, l = 2; l <= c; i++, l <<= 1) for(int j = 0; j + l <= c; j++) Min[i][j] = min(Min[i - 1][j], Min[i - 1][j + (l >> 1)]); }
voidsmall_init(){ // 块内预处理 for (int i = 0; i <= c; i++) for (int j = 1; j < b && i * b + j < t; j++) if(/* 4 */) Dif[i] |= 1 << (j - 1); for(int S = 0; S < (1 << (b - 1)); S++) { int mx = 0, v = 0; for(int i = 1; i < b; i++) { /* 5 */ if(v < mx) { mx = v; Pos[S] = i; } } } }
node *ST_query(int l, int r){ int g = Log2[r - l + 1]; returnmin(Min[g][l], Min[g][r - (1 << g) + 1]); }
node *small_query(int l , int r){ // 块内查询 int p = l / b; int S = /* 6 */; return A[l + Pos[S]]; }
node *query(int l, int r){ if(l > r) returnquery(r, l); int pl = l / b, pr = r / b; if (pl == pr) { returnsmall_query(l, r); } else { node *s = min(small_query(l, pl * b + b - 1), small_query(pl * b, r)); if(pl + 1 <= pr - 1) s = min(s, ST_query(pl + 1, pr - 1)); return s; } }
intmain(){ int m; cin >> n >> m; for (int i = 0; i < n; i++) cin >> T[i].val; build(); DFS(root); ST_init(); small_init(); while(m--) { int l, r; cin >> l >> r; cout << query(T[l].dfn, T[r].dfn)->val << endl; } return0; }
①处应填( ) A. p->son[0] = S[top--] B. p->son[1] = S[top--] C. S[top--]->son[0] = p D. S[top--]->son[1] = p
解析:
一和二都是建立笛卡尔树的代码,我们肯定是用单调栈解决,找到最大的左儿子,所以选 A
②处应填( ) A. p->son[0] = S[top] B. p->son[1] = S[top] C. S[top]->son[0] = p D. S[top]->son[1] = p
解析:
这里也是上面建立笛卡尔树的代码,上一题操作结束后,栈顶元素一定是比当前元素大的,必须覆盖,也就是说选 D
③处应填( ) A. x->dep < y->dep B. x < y C. x->dep > y->dep D. x->val < y->val
解析:
建立完 笛卡尔树,val 就已经变成了无用的变量,排除 D
B 选项完全就是胡扯也排除,现在剩下 AC,我们要求最小值肯定是选 A
④处应填( ) A. A[i * b + j - 1] == A[i * b + j]->son[0] B. A[i * b + j]->val < A[i * b + j - 1]->val C. A[i * b + j] == A[i * b + j - 1]->son[1] D. A[i * b + j]->dep < A[i * b + j - 1]->dep
解析:
按照题目的表述,我们要用深度解决,所以说选 D
⑤处应填( ) A. v += (S >> i & 1) ? -1 : 1 B. v += (S >> i & 1) ? 1 : -1 C. v += (S >> (i - 1) & 1) ? 1 : -1 D. v += (S >> (i - 1) & 1) ? -1 : 1
解析:
首先 i 是从一开始的,所以选 CD 中的一个。其次题目已经说明,后者小于前者是 1,所以选 D
⑥处应填( ) A. (Dif[p] >> (r - p * b)) & ((1 << (r - l)) - 1) B. Dif[p] C. (Dif[p] >> (l - p * b)) & ((1 << (r - l)) - 1) D. (Dif[p] >> ((p + 1) * b - r)) & ((1 << (r - l + 1)) - 1)