题解:P12074 [OOI 2025] The arithmetic exercise
比较神秘的题目。
考虑既然
设
则
那么一个加,一个减,不好看,变化为:
那么发现一个非常有趣的性质,由于
那么不妨把
一眼丁真,鉴定为 slope trick。
凸性如何证明,设
-
若
i 为偶数,那么f_{i,j}=f_{i-1,j-1}+\max(\Delta_{i-1,j},2x_i) 。那么前面一段会选择
\Delta ,后面一段会选择2x_i 。考虑取到
\Delta 的那一段,有:\Delta_{i,j}=f_{i,j}-f_{i,j-1}=(f_{i-1,j-1}+\Delta_{i-1,j})-(f_{i-1,j-2}+\Delta_{i-1,j-1})=\Delta_{i-1,j} 对于取到
2x_i 那一段,更简单,\Delta_{i,j}=\Delta_{i-1,j-1} 。对于分界点,
\Delta_{i,k}=(f_{i-1,k-1}+2x_i)-(f_{i-1,k-2}+\Delta_{i-1,k-1})=2x_i 由于有
2x_i\ge \Delta_{i-1,k}=\Delta_{i,k+1} ,那么显然\Delta 继续单调递增。 -
若
i 为奇数,那么f_{i,j}=f_{i-1,j}+\max(2x_i,\Delta_{i-1,j+1}) 。那么前面一段会选择
\Delta ,后面一段会选择2x_i 。考虑取到
\Delta 的那一段,有:\Delta_{i,j}=f_{i,j}-f_{i,j-1}=(f_{i-1,j}+\Delta_{i-1,j+1})-(f_{i-1,j-1}+\Delta_{i-1,j})=\Delta_{i-1,j+1} 对于取到
2x_i 那一段,更简单,\Delta_{i,j}=\Delta_{i-1,j} 。对于分界点,
\Delta_{i,j}=(f_{i-1,j}+2x_i)-(f_{i-1,j-1}+\Delta_{i-1,j})=2x_i
那么直接用 multiset 维护这个
细节:
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define p_b push_back
#define m_p make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
#define gcd __gcd
#define lowbit(x) (x&(-x))
using namespace std;
int rd(){
int x=0,f=1; char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
return x*f;
}
void write(int x){
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=3e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n,m,a[N],ans,val;
multiset<int,greater<int> > s;
void solve(){
n=rd();m=rd();for(int i=1;i<=m;i++)a[i]=rd(),val-=a[i];
reverse(a+1,a+1+m);
for(int i=1;i<=m;i++){
s.insert((a[i]<<1ll));
if(i&1) val+=(*s.begin()),s.erase(s.begin());
int lim=(n+2-(i&1))>>1;
while(s.size()>=lim) s.erase(prev(s.end()));
}
ans=val;
for(auto u : s) val+=u,ans=max(ans,val);
printf("%lld\n",ans);
}
void clean(){
ans=val=0;
s.clear();
}
signed main(){
int T=rd();while(T--)solve(),clean();
return 0;
}