Day 1
每排有两个座位,所以只可能是一个内向的先坐下,然后一个外向的再坐下。同时,要考虑座位的宽度。
不难想到定义一个小根堆和一个大根堆,分别表示内向和外向的人可以坐的座位。开始时,所有座位的宽度放到小根堆里,每次内向的人就选顶部的座位。同时,把这个选择的座位放进大根堆里。这个座位就满足已经有一个内向的人。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
看到输入可能有重复,不难想到用 set
去重。每次用所有题目的全集在参加学生中筛选题目。对于比赛,只要学生的题目和目前的题目有重复,那就删掉它;对于训练,如果目前某一题目有人没有做过(即没有重复),就删掉它。
输出从小到大,而 set
内部有序,直接输出剩下的题目。
因为每次要不断删除题目,局部接近 log 级,时间复杂度为 Θ ( n k log m ) \Theta(nk\log m) Θ(nklogm)(也许并不准确)。
Day 2
首先,第 k k k 优解必定由目前的前 k k k 优解转移过来。注意原先的转移方程: d p j = max ( d p j , d p j − w i + v i ) dp_j=\max(dp_j,dp_{j-w_i}+v_i) dpj=max(dpj,dpj−wi+vi)。不难想到用两个数组记录下 max 里的两个值。在原有的 d p dp dp 基础上再加一维,表示第几优解。
利用归并排序的思想,不断用两个数组的值更新前 k k k 优解。
时间复杂度 O ( n v k ) O(nvk) O(nvk)。
for(int i = 1;i <= n; ++i)
for(int v = V;v >= w[i]; --v) {
int a[Maxn], b[Maxn];
for(int j = 1;j <= k; ++j)
a[j] = dp[v - w[i]][j] + c[i], b[j] = dp[v][j];
int x = 1, y = 1, z = 1;
a[k + 1] = b[k + 1] = -1;
while(z <= k and (a[x] != -1 or b[y] != -1)) {
if(a[x] > b[y]) dp[v][z] = a[x++];
else dp[v][z] = b[y++];
if(dp[v][z] != dp[v][z - 1]) z ++;
}
}
Day 3
难点是求间隔的战舰。
分别记录每个点到根节点的距离,并查集的长度。
合并两个并查集 x x x 和 y y y 时,可以对并查集的长度进行修改。将 y y y 到 x x x 的距离更新为原来 x x x 的长度。
这样就有效处理了根节点,那每个子节点怎么更新呢?
只需要在查找的时候,顺带把子节点加上父节点到根的长度。
朋友之间不难求,但是敌人呢?
构造虚点,把敌人归在 [ n + 1 , 2 n ] [n+1,2n] [n+1,2n] 的编号中,这样敌人的敌人还是会在 [ 1 , n ] [1,n] [1,n] 中并与这个人属一个集合。统计时,还是只看 [ 1 , n ] [1,n] [1,n],忽略敌人。
封圈时,圈中的所有点都是连通的。只要加入这个两点的时候发现它们在同一个并查集中,就是封圈。
注意点的存储,为避免重复,把二维坐标转化成点 x ∗ n + y x * n + y x∗n+y。
7.27测试
枚举起点,分别构造最小生成树。
把每个点连接的边权 d i d_i di 事先设成 v i v_i vi,在求解过程中再更新 d i d_i di。
时间复杂度 O ( n 3 ) O(n^3) O(n3)。
不难发现:建造一个发电站,就是一个自环,如何处理呢?对于每个点,都有一个自环。而且必须保证至少有一个点要走这个自环。不妨引入一个虚点 0 0 0,让每个点的自环都变成 0 0 0 到 i i i 的边。讨论正确性。
最小生成树是图中的一个联通块。因为必须有一个点与 0 0 0 连接,所以加上 0 0 0 之后,仍是连通的。
时间复杂度 O ( n 2 ) O(n^2) O(n2)。
易得守卫有 n + m n+m n+m 个,思考怎么维护代价。
观察到 n , m , n m ≤ 1 0 5 n,m,nm\leq 10^5 n,m,nm≤105,正常的二维数组存储肯定会爆,想到图。
把它的横纵坐标分别作为起点和终点,为了避免点重复,将终点加上 n n n,这样就变成 i i i 到 j + n j+n j+n 之间存在一条长度为 w i , j w_{i,j} wi,j 的边。
每一行 i i i 与某一列 j j j 相连,维护的是行。某一列 j j j 与某一行 i i i 相连且不重复,维护的是列。
这样最小生成树跑出来是 n + m − 1 n+m-1 n+m−1 条边,而要使边数为 n + m n+m n+m,相当于要在树上再连一条边,形成基环树。
求最小基环树即可,类似于 kruskal
。
时间复杂度 O ( n m log ( n + m ) ) O(nm\log(n+m)) O(nmlog(n+m))。
一眼区间dp,对于每个 [ i , i ] [i,i] [i,i],可以确定 i i i 是否有球。同样,知道 [ i , j ] [i,j] [i,j] 和 [ i + 1 , j ] [i + 1,j] [i+1,j] 也可以判定。
时间复杂度 O ( n 3 ) O(n^3) O(n3)。
考虑优化。借助上面的思想,换一种角度:把每个 [ i , j ] [i,j] [i,j] 看作图中的一条边。由于存在有意义的自环 [ i , i ] [i,i] [i,i],为了不影响结果,只需要看作是 [ i − 1 , i ] [i-1,i] [i−1,i] 即可。因此,存的 [ i , j ] [i,j] [i,j] 也要变成 [ i − 1 , j ] [i-1,j] [i−1,j]。(可以理解为构造虚点)
要知道每个杯子的情况,即要使 [ i − 1 , i ] [i-1,i] [i−1,i] 连通,也就是让整个图连通,又要花费最小,而花费又是边权,问题就转化成了求最小生成树。
时间复杂度 O ( n 2 ) O(n^2) O(n2)。