首页 > 其他分享 >CerealCode

CerealCode

时间:2024-09-25 11:50:11浏览次数:1  
标签:int sum ans MAXN 熊猫 煎饼 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;
}

标签:int,sum,ans,MAXN,熊猫,煎饼,CerealCode
From: https://www.cnblogs.com/yaosicheng124/p/18431034

相关文章