雅礼集训 part1


2017


Day1


市场

实际上算上区间加法增长的部分值域也很低, 对于区间整除最多做 log 次。

所以直接线段树暴力维护。

记录

矩阵

为什么我会默认可以用列给行染色啊?

只能先搞出一行全黑,然后染完所有列。

由于是给列染色,所以对于第 k 行,只要存在某一行的第 k 列是黑,就可以完成补色,且补色的步数一定。

对于实现,考虑一下分支情况就很好做了。

不想写(\kel

字符串

\(q\times k \le 10^5\)

算法一:

每次询问把 w 的所有的子串的 f 处理出来然后计算那个 Σ。

可以莫队算那个 Σ, 也可以预处理后直接在处理 w 的子串的 f 的过程中算一下这个子串在 [a,b] 之间被提到的次数, 后者更好写。

复杂度是 \(O(qk^2\log m)\)

算法二:

考虑预处理后直接计算 Σ。

具体地, 对于每个 w 的每个 endpos, r,算出其最多往前延长到哪里,使得串是 S 的子串, 然后对于每个询问 f (,,l,r), 直接倍增在 parent 树上跳 fa 找到 w[l,r] 对应的节点即可。

不倍增也能过?????

复杂度 \(O(q\log n(k+m))\)

记录


Day2


水箱

考虑最优的答案对应的局面,整个水箱必定被划分成几段, 即 \([1,2,\cdots,n]\) 被划分成 \([1,\cdots,k][k+1,\cdots,p]\cdots[s+1,n]\)

对于相同段, 水位相同且挡板不高于水面, 对于不同段, 有挡板相隔, 相隔的定义是挡板两边的水位不同。

考虑从低到高扫描最低水位, 在这个过程中对所有格子灌水使得所有格子的最低水位恰好为这个最低水位(大概), 水位高于挡板就合并连通块。在这个过程中,所有可能出现的段都会被观测到, 在观测的过程中统计答案, 每个段都要考虑最优的选择是当前水位还是历史上出现过的子段结构的组合。

记录

棋盘游戏

将棋盘黑白染色后建二分图,从某点开始先手必胜当且仅当当前点在所有的最大匹配中都是匹配点, 证明略。

找在某个最大匹配中不是匹配点的方法:首先求任意一个最大匹配,然后从所有非匹配点开始 dfs, 每次遍历与当前点相邻的点 v,v 一定有匹配边,对于与 v 匹配的点 u, dfs(u),给所有 dfs 到的点打上标记,所有打上标记的点都是要找的点。

证明略。

记录

线段游戏

李超树板子。以前写过几次,忘了,这里再整理一下。

首先是存储,对于线段 \(y = kx+b\) , 存储 \((k,b)\)

typedef pair<double,double> linE;

有两个关于线段的函数:

// 一次函数求值
double f (linE l, int x) { return l.first * x + l.second; }
// 求线段交点的横坐标
double inter (linE x, linE y) {
  return (y.second - x.second) / (x.first - y.first);
}

插入逻辑自然,比较好写

#define li (me << 1)
#define ri (li | 1)
#define mid ((l+r)>>1)
#define ls li,l,mid
#define rs ri,mid+1,r
void ins (int me, int l, int r, int x, int y, int id) {
  if (l > r) return ;
  if (x <= l && r <= y) {
    if (! vis[me]) { vis[me] = true, t[me] = id; return ; }
    double ly1 = f (lin[id], l), ry1 = f (lin[id], r),
    ly = f (lin[t[me]], l), ry = f (lin[t[me]], r);
    if (ly1 <= ly && ry1 <= ry) return ;
    if (ly1 >= ly && ry1 >= ry) { t[me] = id; return ; }
    double in = inter (lin[id], lin[t[me]]);
    if (ly1 >= ly) {
      if (in <= mid) ins (ls, x, y, id);
      else ins (rs, x, y, t[me]), t[me] = id;
    } else {
      if (in > mid) ins (rs, x, y, id);
      else ins (ls, x, y, t[me]), t[me] = id;
    }
    return ;
  }
  if (x <= mid) ins (ls, x, y, id);
  if (y > mid) ins (rs, x, y, id);
}

删除逻辑也可, 写起来很舒服。

int lccmp (int X, int x, int y) {
  if (!x || !y) return x | y;
  return f (lin[x], X) > f (lin[y], X) ? x : y;
}
int get (int me, int l, int r, int x) {
  int res = 0;
  if (vis[me]) res = t[me];
  if (l == r) return res;
  return lccmp (x, res, x <= mid ? get (ls, x) : get (rs, x));
}

记录

posted @ 2021-03-10 22:25  xwmwr  阅读(75)  评论(0)    收藏  举报