雅礼国庆集训

2 篇文章 0 订阅
1 篇文章 0 订阅

前言

洒落君臣契,飞腾战伐名。(杜甫《公安县怀古》)

NOIP 前的一个月。
这浸满热血的虔信,真的会化作墓碑吗?
或许明日我们不再是战友,但人生终将有无数个此时。

本文省略以下定义:

#define F(z, u, v) for(int z = (u), des##z = (v); z <= des##z; ++z)
struct Bnd { int f, s; Bnd(int f = 0, int s = 0): f(f), s(s){}}
struct Tup { int f, s, t; Tup(int f = 0, int s = 0, int t = 0): f(f), s(s), t(t){}}
template <typename T> bool chkmax(T& a, T b) { return a < b ? a = b, 1 : 0; }

本文所有源码由命题者提供,格式已调整,并加了注释。

乱入

填一下暑假清北血糖的坑。

复习 维护区间取模、单点修改、区间和。

所以今年暑假我才会写线段树,我太弱了… 记录和的同时记录一个最大值,如果最大值小于模数就跳过即可。

Garden 给定点集 K K K,在矩阵 C \bold C C 上找两点 A , B A,B A,B 使 ∑ i ∈ S C [ i ] \sum\limits_{i\in S} \bold C[i] iSC[i] 最大,其中 S = { i : i = A + j  or  i = B + j , j ∈ K } S = \{i: i=A+j\text{ or }i=B+j, j\in K\} S={i:i=A+j or i=B+j,jK},点按照矢量运算。

棘手的问题在于重复。事实上根据抽屉原理,每个点只需选 ∣ K ∣ 2 + 1 |K|^2 + 1 K2+1 个,就会有一个不重复的。因此每个点最大的 ∣ K ∣ 2 + 1 |K|^2 + 1 K2+1 个即可。

D1

养花 静态区间询问模以某数后的最大值。

分块。 预处理所有除数的结果,块外暴力,块内查表。

F(i, 1, bn) { memset(lst, 0, sizeof lst);
  F(j, (i - 1) * bs, std::min(i * bs, n)) lst[a[j]] = a[j];
  F(j, 1, MAXQ) chkmax(lst[j], lst[j - 1]); // lst[j] 为 j 前最大值
  F(j, 1, n) for(int k = 0; k <= MAXQ; k += j)
    chkmax(ans[i][j], lst[std::min(k + j - 1, MAXQ)] - k); }
  // 取所有 [ik, (i + 1)k) 内最大值

折射 平面上有若干定点,过之作折线,使纵坐标递增且横坐标摆幅减小,求方案数。

前缀和优化。 纵向转移需要 O ( n 3 ) \text O (n^3) O(n3),故横向转移。 d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1] 代表节点 i i i 为顶端,向左/右的方案数。加入一新节点时其在最右,故必在首位或次位。

F(i, 1, n) { dp[i][0] = dp[i][1] = 1;
for(int j = i - 1; j >= 1; j--) 
  if(p[j].y > p[i].y) (dp[j][1] += dp[i][0]) %= MOD;
  else (dp[i][0] += dp[j][1]) %= MOD;
ans = MOD - n; F(i, 1, n) ans = ((ans + dp[i][0]) % MOD + dp[i][1]) % MOD;

画作 在 01 矩阵上每次可以为一个四连块涂色,求从白色画出给定图形的最小步数。

搜索。 最优方案总能等价成一种修改范围逐步缩小的方案。因此,我们可搜索末态的所有点,它所需的涂色次数为最远的黑块加 1(「最远」是经过的四连块最多),尔后取最小值即可。

int bfs(int x, int y) {
  static const int dx[] = { 1, 0, -1, 0 }, dy[] = { 0, 1, 0, -1 }; // 一步之遥
  std::deque<pii> q; memset(dis, -1, sizeof dis);
  dis[x][y] = 0; q.push_back(Bnd(x, y));
  int re = 0; while(!q.empty()) {
    int cx = q.front().f, cy = q.front().s; q.pop_front();
    if(g[cx][cy] == '1') chkmax(re, dis[cx][cy]);
    for(int i = 0; i < 4; ++i) {
      int nx = cx + dx[i], ny = cy + dy[i];
      if(nx >= 0 && nx < n && ny >= 0 && ny < m && dis[nx][ny] == -1)
        if(g[nx][ny] == g[cx][cy])
             dis[nx][ny] = dis[cx][cy],     q.push_front(Bnd(nx, ny));
        else dis[nx][ny] = dis[cx][cy] + 1, q.push_back (Bnd(nx, ny)); }}
  return re; }

// 主函数内:
ans = INF; F(i, 1, n) F(j, 1, m) chkmin(ans, bfs(i, j));
printf("%d\n", ans + 1);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值