1. 程式人生 > >雅禮國慶集訓

雅禮國慶集訓

前言

灑落君臣契,飛騰戰伐名。(杜甫《公安縣懷古》)

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 給定點集 KK,在矩陣 C\bold C 上找兩點 A,BA,B 使 iSC[i]\sum\limits_{i\in S} \bold C[i]

最大,其中 S={i:i=A+j or i=B+j,jK}S = \{i: i=A+j\text{ or }i=B+j, j\in K\},點按照向量運算。

棘手的問題在於重複。事實上根據抽屜原理,每個點只需選 K2+1|K|^2 + 1 個,就會有一個不重複的。因此每個點最大的 K2+1|K|^2 + 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(n3)\text O (n^3),故橫向轉移。dp[i][0/1]dp[i][0/1] 代表節點 ii 為頂端,向左/右的方案數。加入一新節點時其在最右,故必在首位或次位。

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);