2 条题解

  • 0
    @ 2026-5-15 22:57:29
    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    void solve() {
        int n;
        cin >> n;
        vector<int> a(n), b(n);
        for (auto &i: a) cin >> i;
        for (auto &i: b) cin >> i;
        
        // solve
        vector<int> pb(n+1);
        for (int i = 0; i < n; i++) pb[i+1] = pb[i]+b[i];
        vector<int> p(n+1);
        for (int i = 0; i < n; i++) p[i+1] = max(p[i], a[i]-pb[i]);
        vector<int> s(n+1);
        for (int i = n-1; i >= 0; i--) s[i] = max(s[i+1]-b[i],a[i]);
    
        int ans = 1e18;
        for (int i = 0; i < n; i++) {
            ans = min(ans, max(s[i],p[i]-pb[n]+pb[i]));
        }
        cout << ans << '\n';
    }
    
    signed main() {
        cin.tie(0)->sync_with_stdio(0);
        solve();
    }
    
    • 0
      @ 2026-4-29 23:22:09

      知识点

      解题思路

      暴力枚举


      题目中要求选定一个 j1jnj(1 \le j \le n),比太郎从 jj 开始按照

      j,j+1,j+2,,n,1,2,,j1j,j+1,j+2,\cdots,n,1,2,\cdots,j-1

      的顺序打怪。

      我们很容易想到可以把这些怪看做一个环,比太郎打怪的过程相当于从环上一点按一定顺序遍历整个环,进而想到化环为链的思想。

      定义

      Ai+n=Ai,Bi+n=Bi(1i<n)A_{i + n} = A_i,B_{i + n} = B_i(1 \le i < n)

      假设第一次打的怪编号为 j(1jn)j(1 \le j \le n),此时比太郎需要的初始力量的最小值为 PjP_j

      $$P_j=\max_{j \le i < n + j} ( A_i - \sum_{k = i}^{j - 1} B_k)$$

      设比太郎需要的初始力量的最小值(即答案)为 PP

      P=min1jnPjP=\min_{1 \le j \le n} P_j $$P = \min_{1 \le j \le n} (\max_{j \le i < n + j} (A_i - \sum_{k = j}^{i - 1} B_k))$$

      时间复杂度 O(n3)O(n^3),TLE 无疑。

      考虑前缀和优化


      观察这个求和

      k=ji1Bk\sum_{k = j}^{i - 1} B_k

      发现这部分计算可以用前缀和将时间复杂度优化成 O(1)O(1)

      定义前缀和数组

      sumi=j=1iBjsum_i = \sum_{j = 1}^{i} B_j

      $$\sum_{k = j}^{i - 1} B_k = sum_{i - 1} - sum_{j - 1}$$

      $$P = \min_{1 \le j \le n} (\max_{j \le i < n + j} (A_i - (sum_{i - 1} - sum_{j - 1})))$$$$P = \min_{1 \le j \le n} (\max_{j \le i < n + j} (A_i - sum_{i - 1} + sum_{j - 1}))$$$$P = \min_{1 \le j \le n} (\max_{j \le i < n + j} (A_i - sum_{i - 1}) + sum_{j - 1})$$

      为方便计算,设 Wi=Aisumi1W_i=A_i - sum_{i - 1},则

      $$P = \min_{1 \le j \le n} (\max_{j \le i < n + j} (W_i) + sum_{j - 1})$$

      时间复杂度 O(n2)O(n^2),还是 TLE。

      考虑使用单调队列


      看出来了吗?这题就相当于在 WW 数组里寻找定长区间最大值,变成了一道模版题,可以参考模版题P1886

      时间复杂度降到 O(n)O(n),顺利通过!

      代码奉上

      #include<bits/stdc++.h>
      using namespace std;
      //不开long long见祖宗 
      #define ll long long
      const ll MAXN=5e5+10,MAXLL=4611686018427387903;
      ll n,a[2*MAXN],b[2*MAXN],sum[2*MAXN],w[2*MAXN],q[2*MAXN],ans=MAXLL;
      int main() {
      	scanf("%lld",&n);
      	for(int i=1; i<=n; i++) {
      		scanf("%lld",&a[i]);
      		a[i+n]=a[i];
      	}
      	for(int i=1; i<=n; i++) {
      		scanf("%lld",&b[i]);
      		b[i+n]=b[i];
      	}
      	//前缀和 
      	//计算sum[]、w[] 
      	for(int i=1; i<=2*n-1; i++) {
      		sum[i]=sum[i-1]+b[i];
      		w[i]=a[i]-sum[i-1];
      	}
      	//使用单调队列 
      	int head=1,tail=0;
      	for(int i=1; i<=n-1; i++) {
      		while(w[q[tail]]<=w[i]&&head<=tail) tail--;
      		q[++tail]=i;
      	}
      	for(int i=n; i<=2*n-1; i++) {
      		while(q[head]<i-n+1&&head<=tail) head++;
      		while(w[q[tail]]<=w[i]&&head<=tail) tail--;
      		q[++tail]=i;
      		ans=min(ans,w[q[head]]+sum[i-n]);
      	}
      	printf("%lld",ans);
      	return 0;
      }
      
      • 1

      [JOI 2025 Final] 勇者比太郎 2 / Bitaro the Brave 2

      信息

      ID
      9061
      时间
      1000ms
      内存
      1024MiB
      难度
      7
      标签
      递交数
      50
      已通过
      11
      上传者