CerealCode

GYM 105310 C

题目描述

\(N\) 个煎饼店围成一圈,第 \(i\) 个店中有 \(p_i\) 个煎饼。接下来两只红熊猫会进行以下操作:

  • 两只熊猫分别选择一个不同的店 \(a,b\)。第一只先选。
  • 接着第一个熊猫选择一个不为 \(b\) 的店,从 \(a\) 开始沿着一条不经过 \(b\) 的路线走到该店,并把路径上的店中的煎饼全部吃掉。
  • 然后第二个熊猫选择一个没被第一个熊猫经过的店,从 \(b\) 开始沿着一条不经过第一只熊猫经过的店的路线走到该店,并把路径上的店中的煎饼全部吃掉。

两只熊猫都想最大化自己吃的煎饼数量,求第一只熊猫会吃多少个煎饼。

思路

我们考虑枚举 \(a\),并看第二只熊猫会怎么做。

假设此时第二只熊猫已经选好 \(b\) 了,那么此时在第一只熊猫面前有两条路,第一只熊猫肯定会把这条路上能吃的吃完,并且选择煎饼更多的那条。此时第二只就只能吃更少的那条。

所以第二只熊猫得到的煎饼 \(f(b)\) 是一个单峰函数,因为这是两个单调函数的 \(\min\)。我们就可以使用二分,在峰的位置是最后一个 \(f(b)-f(b-1)\ge 0\) 的位置。通过二分出的 \(b\) 就可以求出第一只熊猫的煎饼数。

空间复杂度 \(O(N)\),时间复杂度 \(O(N\log N)\)

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 300001;

int t, n, a[MAXN];
ll sum[MAXN], ans;

ll Calc(int a, int b) {
  return min(sum[b] - sum[a], sum[a + n - 1] - sum[b - 1]);
}

int Binary_Search(int x) {
  int l = x + 1, r = x + n - 1;
  for(; l < r; ) {
    int mid = (l + r + 1) >> 1;
    (Calc(x, mid) - Calc(x, mid - 1) >= 0 ? l = mid : r = mid - 1);
  }
  return l;
}

void Solve() {
  cin >> n;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    a[n + i] = a[2 * n + i] = a[i];
    sum[i] = sum[i - 1] + a[i];
  }
  for(int i = n + 1; i <= 3 * n; ++i) {
    sum[i] = sum[i - 1] + a[i];
  }
  ans = 0;
  for(int i = 1; i <= n; ++i) {
    int x = Binary_Search(i);
    x -= (x > 2 * n ? 2 : (x > n ? 1 : 0)) * n;
    if(x < i) {
      ans = max({ans, sum[i] - sum[x], sum[x + n - 1] - sum[i - 1]});
    }else {
      ans = max({ans, sum[x - 1] - sum[i - 1], sum[i + n] - sum[x]});
    }
  }
  cout << ans << "\n";
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}

GYM 105310 D

题目描述

给定两个字符串 \(s,t\),我们定义字母 \(x\) 的值为其在字母表中的下表(a\(0\))。我们还定义:

  • 一个字母 \(x\)反转为值为 \(25-x\) 的字母。
  • 一个字母 \(x\)相对为值为 \((x+13)\bmod 26\) 的字母。

每次你可以将一个区间变成他的反转或相对,求将 \(s\) 变为 \(t\) 的最少次数。如果不行输出 \(-1\)

思路

推一推便可以发现,先做反转再做相对和先做相对再做反转是一样的,而且这两种操作只有可能做 \(0/1\) 次。

所以令 \(dp_{0/1,0/1,i}\) 表示考虑将前 \(i\) 个字符变相同,最后一个位置是/否做反转,是/否做相对的最少次数。

转移时,如果上一个位置没做反转,但当前做了,那么要多进行一次操作,如果上一个位置没相对,但当前相对了,那么也要多进行一次操作。

时空复杂度均为 \(O(N)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1000001, INF = 2 * MAXN;

int n, dp[2][2][MAXN];
string s, t;

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> s >> t;
  s = ' ' + s, t = ' ' + t;
  for(int i = 0; i <= n; ++i) {
    for(bool op : {0, 1}) {
      for(bool op2 : {0, 1}) {
        dp[op][op2][i] = INF;
      }
    }
  }
  dp[0][0][0] = 0;
  for(int i = 1; i <= n; ++i) {
    for(bool op : {0, 1}) {
      for(bool op2 : {0, 1}) {
        int x = ((op ? 25 - (s[i] - 'a') : (s[i] - 'a')) + op2 * 13) % 26;
        if(x == t[i] - 'a') {
          for(bool lop : {0, 1}) {
            for(bool lop2 : {0, 1}) {
              dp[op][op2][i] = min(dp[op][op2][i], dp[lop][lop2][i - 1] + (op && !lop) + (op2 && !lop2));
            }
          }
        }
      }
    }
  }
  int ans = min({dp[0][0][n], dp[0][1][n], dp[1][0][n], dp[1][1][n]});
  cout << (ans == INF ? -1 : ans);
  return 0;
}

GYM 105310 G

题目描述

有一个 \(N+2\)\(N+2\) 列的网格图,每行,列依次编号 \(0,1,\dots,N+1\)。其中有 \(M\) 个城市,第 \(i\) 个城市位于 \((x_i,y_i)\)

你将按顺序建造道路:

  • 从四个边界中的任意一个边界开始,朝着对面一直修路,直到到达对面或遇到另一条道路。

你不能在边界上修路。

求将这些城市变得连通所需的最小道路总长。

思路

首先第一条道路肯定会贯穿整张图。而接下来的两条道路必定与第一条垂直,就像这样:

image

因为要是不是这样,否则就只有可能这样:

image-20241001225146762

而这种情况很明显两边不连通。

所以这样我们就把整张图分成了四块,而每一块上的道路只能连接到对应中间的边界,所以可以用 dp 求解。

时空复杂度均为 \(O(N^2+M)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 2005;

int n, m, dp[4][MAXN][MAXN], sum[MAXN][MAXN], maxx[4][MAXN][MAXN], maxy[4][MAXN][MAXN], ans = int(1e9);

int Calc(int x, int y, int x2, int y2) {
  return sum[x2][y2] - sum[x - 1][y2] - sum[x2][y - 1] + sum[x - 1][y - 1];
}

void work(int op, int lx, int rx, int ly, int ry, int dx, int dy) {
  for(int i = lx; ; i += dx) {
    for(int j = ly; ; j += dy) {
      maxx[op][i][j] = (dx == 1 ? max({maxx[op][i][j], maxx[op][i - dx][j], maxx[op][i][j - dy]}) : min({maxx[op][i][j], maxx[op][i - dx][j], maxx[op][i][j - dy]}));
      maxy[op][i][j] = (dy == 1 ? max({maxy[op][i][j], maxy[op][i - dx][j], maxy[op][i][j - dy]}) : min({maxy[op][i][j], maxy[op][i - dx][j], maxy[op][i][j - dy]}));
      if(j == ry) {
        break;
      }
    }
    if(i == rx) {
      break;
    }
  }
}

void DP(int op, int lx, int rx, int ly, int ry, int dx, int dy) {
  for(int i = lx; ; i += dx) {
    for(int j = ly; ; j += dy) {
      int x = maxx[op][i - dx][j - dy], y = maxy[op][i - dx][j - dy];
      if((dx == 1 ? (x > 0) : (x <= n)) && (dy == 1 ? (y > 0) : (y <= n))) {
        dp[op][i][j] = min(dp[op][x][j] + (dy == 1 ? j : n + 1 - j), dp[op][i][y] + (dx == 1 ? i : n + 1 - i));
      }
      if(j == ry) {
        break;
      }
    }
    if(i == rx) {
      break;
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for(int i = 0; i <= n + 1; ++i) {
    for(int j = 0; j <= n + 1; ++j) {
      maxx[1][i][j] = maxx[3][i][j] = maxy[2][i][j] = maxy[3][i][j] = n + 1;
    }
  }
  for(int i = 1, x, y; i <= m; ++i) {
    cin >> x >> y;
    sum[x][y]++;
    maxx[0][x][y] = maxx[1][x][y] = maxx[2][x][y] = maxx[3][x][y] = x;
    maxy[0][x][y] = maxy[1][x][y] = maxy[2][x][y] = maxy[3][x][y] = y;
  }
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= n; ++j) {
      sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
    }
  }
  work(0, 1, n, 1, n, 1, 1), work(1, n, 1, 1, n, -1, 1), work(2, 1, n, n, 1, 1, -1), work(3, n, 1, n, 1, -1, -1);
  DP(0, 1, n, 1, n, 1, 1), DP(1, n, 1, 1, n, -1, 1), DP(2, 1, n, n, 1, 1, -1), DP(3, n, 1, n, 1, -1, -1);
  for(int i = 1; i <= n; ++i) {
    int Min = int(1e9), Min2 = int(1e9), Min3 = int(1e9), Min4 = int(1e9), pos = 0, pos2 = 0;
    for(int j = 1; j <= n; ++j) {
      if(Min > dp[0][i][j] + dp[2][i][j] + (Calc(1, 1, i - 1, n) > 0) * i) {
        pos = j;
      }
      Min = min(Min, dp[0][i][j] + dp[2][i][j] + (Calc(1, 1, i - 1, n) > 0) * i);
      if(Min2 > dp[1][i][j] + dp[3][i][j] + (Calc(i + 1, 1, n, n) > 0) * (n + 1 - i)) {
        pos2 = j;
      }
      Min2 = min(Min2, dp[1][i][j] + dp[3][i][j] + (Calc(i + 1, 1, n, n) > 0) * (n + 1 - i));
      Min3 = min(Min3, dp[0][j][i] + dp[1][j][i] + (Calc(1, 1, n, i - 1) > 0) * i);
      Min4 = min(Min4, dp[2][j][i] + dp[3][j][i] + (Calc(1, i + 1, n, n) > 0) * (n + 1 - i));
    }
    ans = min({ans, n + 1 + Min + Min2, n + 1 + Min3 + Min4});
  }
  cout << ans;
  return 0;
}
posted @ 2024-09-25 11:54  Yaosicheng124  阅读(13)  评论(0编辑  收藏  举报