题目链接:传送门
题目思路:
k 次置零操作等价于将原数组,分为k+1段,且任意两段之间是独立的,相互之间没有影响;
设某一段为 序列b (以下标1为开头) ,序列长度为L, 其中每一个数字对 answer 的贡献为 b1 * ( L - 1 ) + b2 * ( L - 2 ) + b3 * ( L - 3 ) + ... + bL * 0 ,
根据排序不等式 : 逆序和 <= 乱序和 <= 正序和
可知,要使 answer 最大 ,即使正贡献尽可能大(前缀和为正) 肯定是从大到小排序;
对于 负贡献要尽可能小(前缀和为负),显然应该把负数从小到大依次放入每一段 序列的倒数第一个(bL * 0 ),k+1 段序列的倒数第一个放满后,再往倒数第二个放,依次类推。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 typedef unsigned long long uLL; 5 typedef pair<int,int> pii; 6 typedef pair<LL,LL> pLL; 7 typedef pair<double,double> pdd; 8 const int N=2e6+5; 9 const int M=1e7+5; 10 const int inf=0x3f3f3f3f; 11 const LL mod=998244353; 12 const double eps=1e-8; 13 const long double pi=acos(-1.0L); 14 #define ls (i<<1) 15 #define rs (i<<1|1) 16 #define fi first 17 #define se second 18 #define pb push_back 19 #define eb emplace_back 20 #define mk make_pair 21 #define mem(a,b) memset(a,b,sizeof(a)) 22 LL read() 23 { 24 LL x=0,t=1; 25 char ch; 26 while(!isdigit(ch=getchar())) if(ch=='-') t=-1; 27 while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); } 28 return x*t; 29 } 30 int a[N]; 31 32 int main() 33 { 34 int n=read(),k=read(); 35 for(int i=1;i<=n;i++) a[i]=read(); 36 sort(a+1,a+n+1); 37 LL sum=0,ans=0; 38 int i; 39 for(i=n;i;i--) 40 { 41 ans+=sum; 42 sum+=a[i]; 43 if(sum<0) break; 44 } 45 //for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?' ':' '); 46 //printf("%lld, i=%d ",ans,i); 47 a[i]=sum; 48 for(int j=1;j<=i;j++) 49 { 50 //printf("%d %d ",(j-1)/k,a[j+1]); 51 ans+=1LL*(j-1)/(k+1)*a[j]; 52 } 53 printf("%lld ",ans); 54 return 0; 55 }