TJ

题目描述

\(n\) 道题需要按顺序验,验第 \(i\) 道题会让比赛的安全度增加 \(a_i\)

由于时间紧迫,你决定只验其中 \(m\) 道题,跳过剩下的题。

连续跳过若干道题时,前 \(k\) 道题每道会让安全度降低 \(b\),剩余每道会让安全度降低 \(c\)

比如当 \(k=4\) 时,如果连续跳过 \(5\) 道题会让安全度降低 \(4\times b+ 1\times c\),如果连续跳过 \(2\) 道题会让安全度降低 \(2\times b\)

求安全度的最大值是多少。

格式

输入格式

第一行包含两个整数 \(n,m\),分别表示题的总数量和你决定验的数量。

第二行包含 \(n\) 个整数 \(a_i\),分别表示验每道题使得安全度增加的值。

第三行包含三个整数 \(k,b,c\),表示连续跳过多道题时,前 \(k\) 道题每道会让安全度降低 \(b\),剩余每道会让安全度降低 \(c\)

输出格式

输出一个整数表示安全度的最大值。

样例

样例输入 #1

8 2
1 3 2 1 6 4 1 1
1 1 100

样例输出 #1

-294

样例解释 #1

使得安全度的最大的其中一种验题方案为:验第 \(2,5\) 道题,总得分为 \((-1)+3+(-1)+(-100)+6+(-1)+(-100)+(-100)=-294\)

数据规模

对于 \(20\%\) 的数据,\(n\leq 200\)

另有 \(10\%\) 的数据,\(k=1\)

另有 \(10\%\) 的数据,\(b=c\)

对于 \(100\%\) 的数据,\(1\leq m\leq n\leq 6000\)\(1\leq a_i\leq 10^4\)\(1\leq k\leq n\)\(1\leq b\leq c\leq 10^4\)

思路

\(dp_{i,j} 前j题已经验了i题的最大安全值,第j题要验\)

分两类转移:设上次验题位置为 \(p-1\)

  1. 上一次验题的位置距离此时不超过 \(k\),即\(j-p\),用单调队列维护 \(p\)\(dp_{i,j}=dp_{i-1,p-1}-b\times (j-p)=dp_{i-1,p}-b\times (j)+b\times p+a_j\),用单调队列维护 \(dp_{i-1,p}+ b\times (p+1))\) 其实是 \(b\times p\) 但是写 \(b\times (p+1)\) 更方便。
  2. 上一次验题的位置距离此时超过 \(k\),所以用 mx 记录前缀的 \(dp_{i-1,j-k-1}+c\times (j-k)\)

第二步推导:

然后 mx 是个前缀,和上面那一段就是一样的了,将 mx 代入( mx 中的 \(j-k\)\(p\))。

\(dp_{i,j}=dp_{i-1,p-1}-b\times k-c\times (j-p-k)+a_j\\=dp_{i-1,p-1}-b\times k-c\times j+c\times p+c\times k\\=dp_{i-1,p-1}+c \times p+c\times k-c\times j\\=mx+c\times k-c\times j\)

代码

#include<bits/stdc++.h>
#define int long long
#define IN_ONLINE 0
using namespace std;
const string file="";
const int ralsei=0;
int n,m;
int dp[6010][6010];
int a[6010];
int k,b,c;
int calc(int l,int r)
{
    return (r-l+1<=k?b*(r-l+1):b*k+c*(r-l+1-k));
}
signed main()
{
#if IN_ONLINE
    freopen((file+".in").c_str(),"r",stdin);
    freopen((file+".out").c_str(),"w",stdout);
#endif 
    ios::sync_with_stdio(ralsei);
    cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    cin>>k>>b>>c;
    int ans=INT_MIN;
    memset(dp,-0x3f,sizeof(dp));
    for(int i=1;i<=m;i++)
    {
        deque<int> q;
        dp[i-1][ralsei]=ralsei;
        int mx=INT_MIN;
        for(int j=i;j<=n;j++)
        {
            /*第一种*/
            while(!q.empty()&&dp[i-1][q.back()-1]+b*q.back()<=dp[i-1][j-1]+b*j)
            {
                q.pop_back();
            }
            q.push_back(j);
            while(!q.empty()&&j-q.front()>k)
            {
                q.pop_front();
            }
            dp[i][j]=dp[i-1][q.front()-1]-calc(q.front(),j-1)+a[j];
            /*第二种*/
            dp[i][j]=max(dp[i][j],a[j]+mx-k*b-c*j+c*k);
            if(j>=k+1)
            {
                mx=max(mx,dp[i-1][j-k-1]+c*(j-k));
            }
            if(i == m)
            {
                ans=max(ans,dp[i][j]-calc(j+1,n));
            }
        }
    }
    cout<<ans<<'\n';
    return ralsei;
}
posted @ 2026-03-16 15:07  ltl0825  阅读(11)  评论(0)    收藏  举报