JOIST2023 传统题记录

D1T1 Two Currencies

直接二分就好了,做的时候降智写了莫队。

https://atcoder.jp/contests/joisp2023/submissions/70864956

D1T2 Festivals in JOI Kingdom 2

考虑对答案相等的情况计数。

对时间轴扫描线,同时维护当前两种算法扫描的状态。

记当前正确和错误算法使用的完整区间个数为 \(x,y\),那么有 \(y\le x\le y+1\)

考虑设 \(f_{i,j,0/1/2}\) 表示当前扫描到 \(i\),此时正确算法选的最后一个右端点,其之后有 \(j\) 个左端点未匹配。同时当前扫描状态:

  • \(0\)\(x=y\)\(i\) 是错误算法选取的右端点。
  • \(1\)\(x=y+1\)
  • \(2\)\(x=y\)

状态转移:

  • \(f_{i,j,0}\to f_{i+1,j+1,2}\),添加左端点。
  • \(f_{i,j,1}\to f_{i+1,j+1,1}\),添加左端点。
  • \(f_{i,j,1}\to f_{i+1,j,0}\),给错误算法分配右端点。
  • \(f_{i,j,2}\to f_{i+1,j+1,2}\),添加左端点。
  • \(f_{i,j,2}\to f_{i+1,0,1}\),给正确算法分配右端点。注意此时同时也给已有的 \(j\) 个左端点分配,系数 \((2n-i-1)^{\underline{j}}\)
  • \(f_{i,j,2}\to f_{i+1,0,0}\),两种算法选择了同一个区间。系数 \((2n-i-1)^{\underline{j-1}}j\)

直接实现为 \(O(n^2)\),卡常后能过。

一个卡常前的 $O(n^2)$ 实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int mod;
struct Barrett {
  __uint128_t t;
  Barrett(int mod = 2) {
    t = ((__uint128_t)1 << 64) / mod;
  }
  ll operator () (ll x) {
    x -= ((x * t) >> 64) * mod;
    x -= (x >= mod) * mod;
    return x;
  }
} MOD;
void Add(int &x, ll y) {
  x = MOD(x + y);
}
int Pow(int x, int y) {
  int b = x, r = 1;
  for(; y; b = MOD((ll)b * b), y /= 2) {
    if(y & 1) r = MOD((ll)r * b);
  }
  return r;
}

const int kN = 6005;
int n;
int mul[kN], imul[kN];
int f[kN][kN][3];

void Init(int N = kN - 2) {
  mul[0] = 1;
  for(int i = 1; i <= N; i++) {
    mul[i] = MOD((ll)mul[i - 1] * i);
  }
  imul[N] = Pow(mul[N], mod - 2);
  for(int i = N - 1; ~i; i--) {
    imul[i] = MOD((ll)imul[i + 1] * (i + 1));
  }
}

int Dn(int n, int m) {
  if((n < m) || (m < 0)) return 0;
  return MOD((ll)mul[n] * imul[n - m]);
}

int main() {
  // freopen("1.in", "r", stdin);
  // freopen("1.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> mod;
  MOD = Barrett(mod);
  Init();
  f[0][0][0] = 1;
  for(int i = 0; i < n + n; i++) {
    for(int j = 0; j <= min(i, n + n - i - 1); j++) {
      Add(f[i + 1][j][2], f[i][j][0]);

      Add(f[i + 1][j][0], f[i][j][1]);
      Add(f[i + 1][j + 1][1], f[i][j][1]);

      Add(f[i + 1][j + 1][2], f[i][j][2]);
      Add(f[i + j + 1][0][0], (ll)f[i][j][2] * Dn(n + n - i - 1, j));
      if(j) {
        Add(f[i + j][0][1], MOD((ll)f[i][j][2] * Dn(n + n - i - 1, j - 1)) * j);
      }
    }
  }
  int all = 1;
  for(int i = 1; i < n + n; i += 2) all = MOD((ll)all * i);
  cout << MOD(all + mod - f[n + n][0][0]) << "\n";
  return 0;
}

https://atcoder.jp/contests/joisp2023/submissions/70912996

D1T3 Passport

倒序考虑问题,我们分别从 \(1\)\(n\) 出发,走 \(1=p_1\to p_2\to\cdots\to p_k=i\)\(n=q_1\to q_2\to\cdots\to q_l=i\) 的链。那么所需的步数就是两个序列的并。

观察到,我们找到第一个 \(p_a=q_b=k\),那么在 \(k\to i\) 的路径上,\(p\)\(q\) 需要完全相同,否则是不优的。

如果我们知道了 \(k\),那么 \(1/n\to k\) 的部分实际上可以贪心,具体地,\(1\to k\) 我们可以从 \(k\) 开始,每次取出区间中 \(l\) 最小的点拓展即可。这个可以用倍增实现。

\(k\to i\) 的部分,这个实际上就是区间往点连边,可以直接优化建图 BFS。可以做到 \(O(n\log n)\)

https://atcoder.jp/contests/joisp2023/submissions/70913737

D2T2 Council

考虑枚举主席的编号 \(p\),那么所有还不能确定的提案恰好有 \(\lfloor\frac{N}{2}\rfloor\) 人支持,此时如果副主席支持则不通过。

把这些提案压位用 \(X\) 表示,每个人的状态为 \(Y_i\),那么一个人会导致的不通过提案就是 \(X\ \mathrm{and}\ Y_i\)。因此我们要最小化的就是 \(|X\ \mathrm{and}\ Y_i|\)

这个问题可以用类似轮廓线的做法做到 \(O(n\log n)\) 预处理。具体地,我们令变量 \(S\) 的前 \(w\) 位为 \(Y\),剩下的位为 \(X\) 的对应位,每次把 \(Y\) 的一位转化为 \(X\),并更新 \(\mathrm{popcount}\)

一个这种算法的实现:https://atcoder.jp/contests/joisp2023/submissions/70919530

这种类型的题还有一个在线的 \(O(n\log^2 n)\) 的 DFS 做法 link

一个上面 DFS 做法的实现:https://atcoder.jp/contests/joisp2023/submissions/70919102

D2T3 Mizuyokan 2

考虑单次怎么暴力。可以发现小段的长度总是 \(=1\) 的,那么考虑 \(f_i\) 表示 \(i\) 为一个小段。

转移用一些数据结构可以单 \(\log\),但是这不好拓展。一个观察是大段的长度不会太长,否则可以从中间划一个小段,事实上这个长度是 \(O(\log V)\) 的,因此直接暴力就是 \(O(n\log V)\)

对大段分析一点性质。对于段 \([l,r]\),我们定义它是好的当且仅当 \(\sum\limits_{l\le i\le r}a_i>\max(a_{l-1},a_{r+1})\)。首先我们划出来的段一定是好的,而且可以通过调整说明,我们只需保证划出来的是好段即可,无需保证大段之间间隔 \(=1\)

那么就可以,把所有好段按右端点贪心选。记 \(nxt_r\) 表示当前好段的右端点是 \(r\),下一段的右端点是多少。根据上面的分析 \(nxt_r-r\)\(O(\log V)\) 的。不难 \(O(n\log V)\) 预处理所有 \(nxt\)

而修改也是简单的,把周围 \(O(\log V)\)\(nxt\) 重构即可。

查询是一个弹飞绵羊状物,分块维护可以做到 \(O(n\sqrt n)\)

https://atcoder.jp/contests/joisp2023/submissions/70945722

D3T1 Chorus

先考虑怎么判定一个序列合法。从前往后贪心,每次遇到一个未配的 \(B\) 就把之间的所有 \(A\) 拿去和后面的 \(B\) 依次匹配。

把这个写的形式化一点。定义 \(t_i\) 为第 \(i\)\(B\) 之前有多少个 \(A\)

设我们遇到的 \(B\) 依次是 \(p_1,p_2,\cdots,p_k\),那么有 \(p_{i+1}=t_{p_i}+1\)

考虑对 \(p\) dp。\(f_{i,j}\) 表示 \(p_j=i\) 的代价。

操作实际上就是把某个 \(t\)\(1\)。转移枚举 \(p_{j+1}=k\),代价是 \(\sum\limits_{i\le q<k}\max(t_q-(k-1),0)\)

可以发现,这个代价和 \(j\) 无关,且满足四边形不等式,直接 wqs 二分,内部决策单调性二分一下可以做到 \(O(n\log^2 n)\)

但是这个代价实际上是一个类似一次函数的形式,内部改成斜率优化可以做到线性,总复杂度 \(O(n\log n)\)

https://atcoder.jp/contests/joisp2023/submissions/70997443

D3T2 Cookies

在知道每个盒子大小 \(siz\) 时,一个判定方法是降序排序,对于任意一个前缀 \(i\)\(\sum\limits_{1\le j\le i}siz_j\le \sum\limits_{1\le k\le n}\min(a_k,i)\)

这个条件可以直接 dp。\(f_{i,j}\) 表示 \(i\) 个盒子,总体积 \(j\) 是否可行。转移从大往小加入盒子,背包可以做到 \(O(n^2\log n)\)

这个是 01 序列的形式,bitset 优化做到 \(O(\frac{n^2\log n}{w})\)

https://atcoder.jp/contests/joisp2023/submissions/71057378

好像输出方案的复杂度写假了,但是懒得改了。

D3T3 Tourism

首先这个可以用回滚莫队做到单根号,但是这不是重点。记录一个 \(\mathrm{polylog}\) 的做法。

虚树的形式不是很好处理,考虑表示成到根链的并,然后减掉 \(\mathrm{LCA}\) 到根的点。

对于到根链的并,考虑倒序扫描 \(l\),对于每个点 \(i\) 维护 \(tim_i\) 表示最小的 \(r\),满足 \(r\) 到根链覆盖了 \(l\)

这个每次的变化是链覆盖,可以重链剖分颜色段均摊,用树状数组维护每种 \(tim\) 出现次数即可。复杂度 \(O(n\log^2n+q\log n)\)

https://atcoder.jp/contests/joisp2023/submissions/71058161

D4T2 Security Guard

对于 \(S\le 2\),我们整体减 \(1\) 后就是 \(S_i\in\left\{0,1\right\}\) 的问题,这个答案就是把所有 \(1\) 点删掉(注意这里边还保留),剩下的链数量。

如果 \(S_i\in\left\{0,1\right\}\),对于树的情况是同理的,统计连通块数量,即 \(1+\sum\limits_{S_i=1}(deg_i-1)\)

\(S\) 更大的时候,一个想法是对于每个 \((v-1,v]\),把 \(<v\) 的数看成 \(0\)\(\ge v\) 的数看成 \(1\),按照上面的方法统计求和。事实上这就是对的,证明可以考虑把每次放的人放在其被考虑的层数 \(v\),每次移动对于 \(v\) 单独做即可。

那么对于树的情况,这个的求和就是 \(\sum\limits_{(u,v)\in E}(S_u+S_v)+\max{a}-\sum a\),实际上就是要最小化 \(\sum (S_u+S_v)\)

考虑从新加 \(n-1\) 条边往回调整,最终的形态形如一个菊花图,中心是 \(S\) 最小的点 \(p\)。当前还原的边形如若干个连通块,如果这个连通块不包含 \(p\),则记录唯一的剩余新增条边 \(p\to x\)

每次找出变化量最小的边调整,合并连通块以及内部的边即可。复杂度可以做到 \(O(n\log n)\)

https://atcoder.jp/contests/joisp2023/submissions/71079392

D4T3 Bitaro's Travel

注意到一次转向会使到起点的距离翻倍,于是直接模拟,每次二分跳一段即可。复杂度 \(O(q\log n\log V)\)

https://atcoder.jp/contests/joisp2023/submissions/71079528

posted @ 2025-11-24 22:26  CJzdc  阅读(25)  评论(0)    收藏  举报