列表

详情


NC51243. 特别行动队

描述

你有一支由 n 名预备役士兵组成的部队,士兵从1到n编号,要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i, i + 1, …, i + k)的序列。
编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x为队内士兵初始战斗力之和,即
通过长期的观察,你总结出一支特别行动队的初始战斗力 x将按如下经验公式修正为x':,其中 a, b, c是已知的系数(a < 0)。
作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。试求出这个最大和。
例如, 你有4名士兵,。经验公式中的参数为 a = –1, b = 10, c = –20。此时,最佳方案是将士兵组成 3个特别行动队:第一队包含士兵1和士兵2,第二队包含士兵3,第三队包含士兵 4。特别行动队的初始战斗力分别为4, 3, 4,修正后的战斗力分别为 4, 1, 4。修正后的战斗力和为 9,没有其它
方案能使修正后的战斗力和更大。

输入描述

输入由三行组成。第一行包含一个整数 n,表示士兵的总数。第二行包含三个整数 a,  b,  c,经验公式中各项的系数。第三行包含 n 个用空格分隔的整数 ,分别表示编号为1, 2, …, n的士兵的初始战斗力。

输出描述

输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。

示例1

输入:

4
-1 10 -20
2 2 3 4

输出:

9

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 112ms, 内存消耗: 23384K, 提交时间: 2022-10-11 19:43:51

//dp[i]=max{dp[j]+(a*(sum[i]-sum[j])^2-b*sum[j]))}+c+b*sum[i]
//a*sum[j]^2+dp[j]-b*sum[j]=2*a*sum[i]*sum[j]-a*sum[i]^2-b*sum[i]+dp[i]-c
#include<iostream>
#include<algorithm>
#include<cstring>
#define endl "\n"
using namespace std;
using ll = long long;
const int maxn = 1e6 + 10;
ll sum[maxn],dp[maxn],q[maxn];
ll n,a,b,c,x;
inline ll pow2(ll num)
{
    return num*num;
}
inline ll func(int i)
{
    return a*pow2(sum[i])-b*sum[i]+dp[i];
}
long double slope(int i,int j)
{
    return (long double)(func(i)-func(j))/(long double)(sum[i]-sum[j]);
}
void solve(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>a>>b>>c;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        sum[i]=sum[i-1]+x;
    }
    int head=1,tail=1;
    q[1]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<tail&&slope(q[head+1],q[head])>=(2.0*a*sum[i]))
        {
            head++;
        }
        dp[i]=dp[q[head]]+a*pow2(sum[i]-sum[q[head]])+b*(sum[i]-sum[q[head]])+c;
        while(head<tail&&slope(q[tail],q[tail-1])<=slope(i,q[tail]))
        {
            tail--;
        }
        q[++tail]=i;
    }
    cout<<dp[n]<<endl;
}
int main(void)
{
    solve();
    return 0;
}

C++(clang++11) 解法, 执行用时: 115ms, 内存消耗: 15112K, 提交时间: 2020-10-21 19:08:22

#include<bits/stdc++.h>
#define k(i,j) 1.0*(y[j]-y[i])/(x[j]-x[i])
using namespace std;
const int nn=1001021;
int n,a,b,c,j,i,q[nn];
long long f,sumx,x[nn],y[nn];
int main(){
	scanf("%d%d%d%d",&n,&a,&b,&c);
	while(n--){
		if(j>=i)j=i;
		scanf("%lld",x+(++i)),x[i]=sumx=sumx+x[i];
		if(j>=i)j=i;
		else while(j<i-1&&k(j,j+1)>2*x[i]*a)j++;
		f=y[j]+x[i]*x[i]*a-2*x[i]*x[j]*a+x[i]*b+c;
		y[i]=f+x[i]*x[i]*a-x[i]*b;
		for(;k(i-2,i-1)<=k(i-2,i);i--)
			swap(x[i],x[i-1]),swap(y[i],y[i-1]);
	}return printf("%lld",f),0;
}

上一题