3 solutions

  • 1
    @ 2025-11-17 23:25:59

    首先想到应该是时间复杂度为O(n2n^2)的暴力枚举。读入a[],b[]两个数组,然后依次枚举每个位,让b[i]的取值为0并且把b[i]中的数据存储下来,从1开始枚举得到w的自小值,最后的答案是a[0]减去w的最小值。

    #include<iostream>
    using namespace std;
    const int N=1e5+10;
    int a[N],b[N];
    int main(){
        int n;cin>>n;
        for(int i=0;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++){
            cin>>b[i];
        }
        for(int i=1;i<=n;i++){
            int x=b[i];b[i]=0;
            int w=0,ans=1e9;
            for(int j=1;j<=n;j++){
                w=w+b[j];
                w=w-a[j];
                ans=min(w,ans);
            }
            cout<<a[0]-ans<<" ";
            b[i]=x;
        }
        return 0;
    }
    

    暴力枚举只能过百分之八十的数据,接下来需要进行公式推导。w+i=1nbi1\sum_{i=1}^{n} b_{i-1}>=i=1nai\sum_{i=1}^{n} a_i,那w应该取 i=1nai\sum_{i=1}^{n} a_i-i=1nbi1\sum_{i=1}^{n} b_{i-1}的最大值,这里维护一个数组c[]来依次存储前面我们所说的差值。将b[i]的值赋为0并不影响前半部分的c[i],但是后半部分的c[i]需要再加一个b[i]。所以在这里维护一个数组pre[]存储前i个数中c[i]的最值,再维护一个数组suf[]存储后i个数的最值。最后答案的取值就是max(pre[i],suf[i]+b[i])。

    #include<iostream>//前缀和 
    using namespace std;
    const int N=1e5+10;
    int a[N],b[N],ans[N];
    int c[N],pre[N],suf[N];
    int main(){
    	int n;cin>>n;
    	for(int i=1;i<=n+1;i++)cin>>a[i];
    	for(int i=1;i<=n;i++)cin>>b[i];
    	pre[0]=suf[n+2]=-1e9;
    	for(int i=1;i<=n+1;i++){//需要自己进行公式推导 
    		c[i]=c[i-1]+a[i]-b[i-1];//c[i]是对a[i]求和-b[i]的最大值 
    		pre[i]=max(pre[i-1],c[i]);
    	}
    	for(int i=n+1;i;--i)suf[i]=max(suf[i+1],c[i]);//后缀的最大值 
    	for(int i=1;i<=n;i++){
    	ans[i]=max(pre[i],suf[i+1]+b[i]);//前缀不影响,后缀加上b[i]即可 
    	cout<<max(ans[i],0)<<" ";	
    	}
    	return 0;
    } 
    
    • 0
      @ 2025-11-19 21:30:19

      前缀和->max前i-1个最大值,倒数(n-i+1)个最大值 1.设置1+n个结点acc(前缀和),每个结点表示在此i结点上需要acc[i]才能到达下一节点,结点acc[0]为a[0],其余1~n的acc[i] = acc[i-1] + a[i] - b[i] 2.求得prefix[i](i属于0~n),prefix[0] =acc[0],其余prefix[i] = max(prefix[i-1] +,acc[i]),表示前i-1至少要满足的和通过结点i需要满足的能量,即为前i个,subfix同理 3.当结点i同学没睡,无法得到b[i],此时对前i-1个结点无影响,对后面有,ans = max(prefix[i-1],sunfix[i]+b[i]),subfix为后面最大数,而因为从i处无法得到b[i],则后面所有数包括subfix[i],都要+b[i].

      #include <iostream>
      #include <vector>
      
      using namespace std;
      
      int main(){
          int n;
          cin>>n;
          vector<int> a(n+1);
          vector<int> b(n+1);
          for(int i= 0;i<=n;i++){
              cin>>a[i];
          }
          for(int i= 1;i<=n;i++){
              cin>>b[i];
          }
          vector<int> acc(n+1);
          vector<int> prefix(1+n);
          vector<int> subfix(1+n);
      
          acc[0] = a[0];
          prefix[0] = a[0];
          for(int i = 1;i <= n;i++){
              acc[i] = acc[i-1] + a[i] - b[i];
              prefix[i] = max(prefix[i-1],acc[i]);
          }
          subfix[n] = acc[n];
          for(int i = n-1;i>0;i--){
              subfix[i] = max(subfix[i+1],acc[i]);
          }
          int ans;
          for(int i = 1;i<=n;i++){
              ans = max(prefix[i-1],subfix[i]+b[i]);
              cout<<ans<<' ';
          }
      }
      
      
      • 0
        @ 2025-5-31 22:48:44

        O(n2)O(n^2) 和二分答案 O(nlogV)O(n\log V) 的做法不在这里讲,这里我们只讲利用前缀/后缀 min\min 性质的 O(n)O(n) 做法。

        我们设 sis_i 为“以 00 号城市为起点”作为前提,从 ii 号城市能够成功出发,巡查所带来的能量总增量(可能为负)。则有:

        • s0=a0s_0=-a_0
        • si=si1+(biai)s_i=s_{i-1}+(b_i-a_i)

        这个不解释,从 ii 出发会先获得 bib_i 的补给,再消耗 aia_i 的能量。

        我们可以对 sis_i 分别做一次前缀 min\min 后缀 min\min,对于以每一个城市为起点的计算,显然其过程中的最小能量总增量决定了答案,最小值的相反数即为答案。

        ii 成功出发到 nn 成功出发的这一段,利用后缀 min\min就可以求了,需要注意的是,此时不存在 bib_i 的补给,这段后缀 min\min 减去 bib_i 即可;而从 00 号城市出发到 i1i-1 号城市出发这一段,正常使用前缀 min\min 去求即可。

        一个边界情况为:当全程的最小能量总增量均 0\ge 0 时,此时答案是 00

        #include <stdio.h>
        #include <algorithm>
        inline int rd()
        {
            int k = 0, f = 1;
            char s = getchar();
            while (s < '0' || s > '9') f = (s == '-') ? 0 : f, s = getchar();
            while (s >= '0' && s <= '9') k = (k << 1) + (k << 3) + (s ^ '0'), s = getchar();
            return f ? k : -k;
        }
        inline void wr(int x)
        {
            if (x < 0) putchar('-'), x = -x;
            if (x > 9) wr(x / 10);
            putchar((x % 10) ^ '0');
        }
        const int N = 100010;
        int n;
        int a[N], b[N];
        
        int pre_s[N], suf_s[N];
        int pre_mn[N], suf_mn[N];
        
        int main()
        {
            n = rd();
            for (int i = 0; i <= n; ++i) a[i] = rd();
            for (int i = 1; i <= n; ++i) b[i] = rd();
        
            pre_s[0] = pre_mn[0] = -a[0];
            for (int i = 1; i <= n; ++i) pre_s[i] = pre_s[i - 1] + (b[i] - a[i]), pre_mn[i] = std::min(pre_mn[i - 1], pre_s[i]);
            suf_mn[n] = pre_s[n];
            for (int i = n - 1; i >= 0; --i) suf_mn[i] = std::min(suf_mn[i + 1], pre_s[i]);
        
            for (int i = 1; i <= n; ++i, putchar(' '))
                wr(-std::min(std::min(pre_mn[i - 1], suf_mn[i] - b[i]), 0));
        }
        
        • 1

        Information

        ID
        41
        Time
        1000ms
        Memory
        512MiB
        Difficulty
        2
        Tags
        # Submissions
        232
        Accepted
        54
        Uploaded By