C Code a Trie
题意:有一个 Trie,其可能被插入了一些串,每一个节点(含根节点)上都有一个值,这些值互不相同。在 Trie 上查询一个串时若是找到了就返回这个串结束节点的值,不然返回最后到达的节点的值。给定若干个查询串及查询结果,问是否存在这样的 Trie,有解时这个 Trie 最少有几个节点。c++
对于一些串,若是它们的查询结果相同,那么对它们的查询都应在它们的 LCA 处结束。因而先对每一个这样的 LCA 打标记,若是一个 LCA 下有多个值不一样的标记显然无解。ide
作完后至关于建了一个原始的符合条件的 Trie,因而再 DFS 一遍以回收尽量多的节点便可。lua
D Defuse the Bombs
最简单的方法是二分最多能活多久,稍微好一点的方法在二分的基础上发现规律,从而仅用一次排序就求出结果。spa
E Escape from the Island
题意:给定一个有向图,通过每条边的时间花费是 1 1 1。一我的能够重复下面的行动序列,直到到达 n n n 号点:将全部有向边视做无向边,从当前点开始移动通过至多 k k k 条边(能够不移动),到达某点后随机选择该点的某条出边(此时不可将有向边视做无向边)并沿该边移动,若是该点无出边则留在原地不动,但仍耗费 1 1 1 单位时间。问对于 ∈ [ 1 , n ] \in [1, n] ∈[1,n] 的每个点 i i i,这我的以 i i i 做为最初起点时,在最坏状况下,他至少要花多少时间才能到达 n n n 号点。注意只要到达了 n n n 号点就算结束。 n ≤ 1 0 5 , k ≤ 50 n \le 10^5, k \le 50 n≤105,k≤50。code
设 f ( i , j ) f(i, j) f(i,j) 表示以 i i i 为起点,此前已经移动过 j j j 条边时,到达 n n n 的最短期。那么显然有
f ( i , j ) = { min ( i , t ) ∈ E ∨ ( t , i ) ∈ E { f ( t , j − 1 ) + 1 } max ( i , t ) ∈ E { f ( t , 0 ) + 1 } f(i, j) = \begin{cases} \min_{(i, t) \in E \vee (t, i) \in E}\left\lbrace f(t, j - 1) + 1\right\rbrace \\ \max_{(i, t)\in E} \left\lbrace f(t, 0) + 1\right\rbrace \end{cases} f(i,j)={ min(i,t)∈E∨(t,i)∈E{ f(t,j−1)+1}max(i,t)∈E{ f(t,0)+1}
在这两种状况中取更小的那个。
blog
因而能够从 n n n 点开始倒着作 BFS 以更新每个状态。每次先作第一种更新,若是对于一个 f ( i , j ) f(i, j) f(i,j) 其全部后继 f ( t , 0 ) f(t, 0) f(t,0) 都计算完了但其自己还未被更新作第二种更新。排序
注意无出边的状况。游戏
#include <bits/stdc++.h> #define MAXN 100005 #define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp) #define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp) using namespace std; int read(){ int f = 1, x = 0; char c = getchar(); while (c < '0' || c > '9'){ if(c == '-') f = -f; c = getchar();} while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar(); return f * x; } int n, m, k, f[MAXN][55]; int at[MAXN], nxt[MAXN << 1], to[MAXN << 1], cnt; int du[MAXN]; bool nodu[MAXN]; void init(){ n = read(), m = read(), k = read(); REP(i, 0, n) REP(j, 0, k) f[i][j] = 0x3f3f3f3f; cnt = 0; memset(at, 0, sizeof(int) * (n + 1)); memset(du, 0, sizeof(int) * (n + 1)); REP(i, 1, m){ int u = read(), v = read(); to[++cnt] = v, nxt[cnt] = at[u], at[u] = cnt; to[++cnt] = u, nxt[cnt] = at[v], at[v] = cnt; ++du[u]; } memset(nodu, 0, sizeof(bool) * (n + 1)); REP(i, 1, n) if (du[i] == 0) nodu[i] = true; } queue<pair<int, int> > q; inline void local_update(int src, int t1, int dest, int t2){ if (f[dest][t2] == 0x3f3f3f3f) f[dest][t2] = f[src][t1] + 1, q.emplace(dest, t2); } void solve(){ REP(i, 0, k) f[n][i] = 0, q.emplace(n, i); while (!q.empty()){ int u = q.front().first, t = q.front().second; q.pop(); if (t > 0){ for (int i = at[u]; i > 0; i = nxt[i]) local_update(u, t, to[i], t - 1); } else { for (int i = at[u]; i > 0; i = nxt[i]){ if (i & 1) continue ; --du[to[i]]; if (!du[to[i]]){ REP(j, 0, k) local_update(u, 0, to[i], j); } } if (nodu[u]){ REP(j, 0, k) local_update(u, 0, u, j); } } } REP(i, 1, n){ printf("%d\n", (f[i][0] == 0x3f3f3f3f ? -1: f[i][0])); } } int main(){ int T = read(); REP(i, 1, T){ printf("Case #%d:\n", i); init(); solve(); } return 0; }
G Game of Cards
题意:有四种牌,点数各为 0、一、二、3,初始局面每种牌各有 c 0 , c 1 , c 2 , c 3 c_0, c_1, c_2, c_3 c0,c1,c2,c3 张。A 和 B 玩游戏,A 先手。当前玩家能够选择现有的牌中点数加起来不超过 3 的两张牌,将其替换成点数为它们点数之和的一张牌。不能操做者输。问谁赢。图片
打表再一次打败了人类智慧。经过打表能够发现答案关于 c 0 c_0 c0 模 2 2 2, c 1 c_1 c1 模 3 3 3 成循环节。因而对于这六种状况直接输出规律便可。get
要特判一些边界状况。
H Hide and Seek
题意:二维格点平面上有两个点,给定这两个点各自离原点的曼哈顿距离(记为 d 01 , d 02 d_{01}, d_{02} d01,d02)以及两点之间的曼哈顿距离(记为 d 12 d_{12} d12),问这两个点有多少种可能的位置 pair。
本题的推导很是依赖画图,而且状况很是多。大体能够画这样一个图。
方便起见,咱们先假设 d 01 ≤ d 02 d_{01} \le d_{02} d01≤d02。
- d 01 = 0 d_{01} = 0 d01=0。若 d 02 = d 12 > 0 d_{02} = d_{12} > 0 d02=d12>0 则答案为 4 d 02 4d_{02} 4d02,若 d 02 = d 12 = 0 d_{02} = d_{12} = 0 d02=d12=0 则答案为 1 1 1,不然答案为 0 0 0。
- d 01 > 0 d_{01} > 0 d01>0。
- d 12 = 0 d_{12} = 0 d12=0。若 d 02 = d 01 d_{02} = d_{01} d02=d01 则答案为 4 d 01 4d_{01} 4d01,不然答案为 0 0 0。
- d 12 < d 02 − d 01 d_{12} < d_{02} - d_{01} d12<d02−d01,则答案为 0 0 0。
- d 12 = d 02 − d 01 d_{12} = d_{02} - d_{01} d12=d02−d01,则答案为 4 ( d 12 + d 01 ( d 12 + 1 ) ) 4(d_{12} + d_{01}(d_{12} + 1)) 4(d12+d01(d12+1))。
- d 02 − d 01 < d 12 < d 02 + d 01 d_{02} - d_{01}<d_{12}<d_{02} + d_{01} d02−d01<d12<d02+d01,则考虑 d 12 − d 02 + d 01 d_{12} - d_{02} + d_{01} d12−d02+d01 是不是偶数。若是不是就意味着以 d 12 d_{12} d12 为半径的“圆”不会和以 d 02 d_{02} d02 为半径的“圆”于任何一个格点相交,答案为 0 0 0。不然答案为 4 ( 2 ⋅ d 12 − d 02 + d 01 + 2 2 + 2 d 01 − 2 ) = 4 ( d 01 + d 02 + d 12 ) 4\left(2\cdot \frac{d_{12} - d_{02} + d_{01} + 2}{2} + 2d_{01} - 2\right) = 4(d_{01} + d_{02} + d_{12}) 4(2⋅2d12−d02+d01+2+2d01−2)=4(d01+d02+d12)。
- d 12 = d 02 + d 01 d_{12}=d_{02} + d_{01} d12=d02+d01,则答案为 4 ( d 02 + d 01 ( d 02 + 1 ) ) 4(d_{02} + d_{01}(d_{02} + 1)) 4(d02+d01(d02+1))。
- 对于更大的 d 12 d_{12} d12,答案为 0 0 0。
J Joy of Handcraft
题意:给定 n n n 个灯,第 i i i 个灯亮度为 x i x_i xi,且在 [ 2 k t i , 2 k t i + t i ] [2kt_i , 2kt_i + t_i] [2kti,2kti+ti] 时间亮,在 [ 2 k t i + t i + 1 , 2 k t i + 2 t i ] [2kt_i + t_i + 1 , 2kt_i + 2t_i] [2kti+ti+1,2kti+2ti] 时间灭,其中 k ≥ 0 , k ∈ Z k \ge 0, k \in \mathbb{Z} k≥0,k∈Z。问对于 ∈ [ 1 , m ] \in [1, m] ∈[1,m] 的每个时刻 j j j,没灭的灯泡中最亮的有多亮。
比较简单的作法是考虑每个时刻会被哪些灯泡更新,这是一个经典的数论分块问题,能够结合 ST 表在 O ( m log m + m m ) O(m \log m + m\sqrt{m}) O(mlogm+mm ) 的时间内作出。常数小的话并不难卡过去。
出题人给的另外一个更好的方法是将每一个周期按亮度排序,而后从大到小更新每个时刻的答案,被更新完的时刻直接删掉。结合并查集就能够作到 O ( m log m + m α ( m ) ) O(m \log m + m\alpha(m)) O(mlogm+mα(m))。
K Knowledge is Power
题意:屡次询问,每次给定一个 n n n,问全部将 n n n 拆分红若干个(至少两个)两两互质的数的拆分方案中,拆出的最大数和最小数的差,最小是多少。 5 ≤ n ≤ 1 0 9 5\le n \le 10^9 5≤n≤109。
分类讨论,对于 6 6 6 无这样的拆分方案。对于奇数能够直接拆成两个相邻的天然数,对于形如 4 k ( k ∈ Z + ) 4k(k \in \mathbb{Z}^+) 4k(k∈Z+) 的偶数拆成 2 k − 1 , 2 k + 1 2k-1, 2k+1 2k−1,2k+1 是最优的。
对于其余偶数,暴力打表发现答案 ≤ 4 \le 4 ≤4。因而枚举状况解方程判断便可。
L Lottery
题意:给定一个可重集 S S S,为 2 a i 2^{a_i} 2ai 的数有 x i x_i xi 个。问 ∣ { ∑ t ∈ T t : T ⊂ S } ∣ |\left\lbrace \sum_{t \in T} t : T \subset S\right\rbrace| ∣{ ∑t∈Tt:T⊂S}∣,即用 S S S 中的数能够拼出多少个不一样的数。
学过多重背包就知道 x i x_i xi 个 2 a i 2^{a_i} 2ai 能够等价地用一些 2 a i , 2 a i + 1 , ⋯ 2^{a_i}, 2^{a_i+1}, \cdots 2ai,2ai+1,⋯ 表示,其中每一个数的出现次数均不超过 2。
这么转换后会发现全部出现过的 2 的指数造成了若干个连续段(如 2 a i , 2 a i + 1 , 2 a i + 2 , ⋯ 2^{a_i}, 2^{a_i+1}, 2^{a_i+2}, \cdots 2ai,2ai+1,2ai+2,⋯),每个段的答案乘起来就是答案,而且段内能够用 DP 计算贡献。因而就作完了。
A A Colorful Grid
有点妙,找机会再补。
F Fracture Ray
有点难写,找机会再补。
I Invaluable Assets
有点没看懂题,找机会再补。
小结
比赛前一天晚上还在赶做业,原本觉得要完蛋了,实际上确实完蛋了(还好队友捞了我一把)。
H 这个题原本应该在最后一小时顺利推出的,结果脑子乱了,推了半天推不出来…
E 最后一小时看了下题目,但没有很快想到拆点的作法…
但愿 ICPC 的时候不要这么捞吧。