题解:P14306 【MX-J27-T3】旋律
题意简述
给定一个序列 \(a_1,a_2, \dots ,a_n\) 和一个正整数 \(k\),取其中一个非空子序列最大化该子序列长度减极差的值。
思路
根据样例解释很容易看出原序列的顺序与答案并无关联。因此想到了可以现将原序列进行排序。假如排序后变为升序排列。
首先明确极差 \(\max(a_1, \ldots, a_n) - \min(a_1, \ldots, a_n)\) 的特性:它只与一个序列的最值相关。由这一条特性,排序后的序列中选择连续的一段,其长度就比不连续一段多,且极差是一样的。因此排序后选择的子序列一定是连续的才可能取到最优。
设序列 \(l,r\) 的“和谐度”为 \(f(l,r)\) 则有:
\[f(l , r) = (r - l + 1) \times k - (a_r - a_l)
\]
由乘法分配律,可以改写为
\[f(l , r) = r \times k - l \times k + k - a_r + a_l
\]
不难想到将 \(l\) 和 \(r\) 相关的分离开来,写成:
\[f(l , r) = (r \times k - a_r)-( l \times k - a_l) + k
\]
发现关于 \(l\) 和 \(r\) 两项的这段是同一个形式!故设 \(b(x) = x \times k - a_x\) 就可以写出:
\[f(l , r) = b(r) - b(l) + k
\]
这样就知道怎么做了吧。
可以先对于每一个 \(l\) 求出使得 \(b(r)\) 尽可能大的 \(r\) 的值,再遍历每一个 \(l\) 求出 \(f(l,r)\) 并取最大值即可。
代码
#include<bits/stdc++.h>
#define ll long long
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100005;
int NaiLoong,T,n;
ll k,a[N],b[N],Max[N];
//l->r:(r-l+1)k-(a_r-a_l)=(r*k-a_r)-(l*k-a_l)+k
int main() {
// freopen("melody.in","r",stdin);
// freopen("melody.out","w",stdout);
ios;cin>>NaiLoong>>T;
while(T--) {
cin>>n>>k;
ll ans=0;
for(int i=1;i<=n;i++) {
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) {
b[i]=k*i-a[i];
}
Max[n+1]=-inf;
for(int i=n;i>=1;i--) {
Max[i]=max(Max[i+1],b[i]);
}
for(int i=1;i<=n;i++) {
ans=max(Max[i]-b[i]+k,ans);
}
cout<<ans<<'\n';
}
return 0;
}
完结撒花喵!
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/19177434

浙公网安备 33010602011771号