题解: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;
}

完结撒花喵!

posted @ 2025-10-30 16:17  Circle_Table  阅读(1)  评论(0)    收藏  举报