cf 1456C. New Game Plus! (分段贪心)

题目链接:传送门

题目思路:

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?'\n':' ');
46     //printf("%lld, i=%d\n",ans,i);
47     a[i]=sum;
48     for(int j=1;j<=i;j++)
49     {
50         //printf("%d %d\n",(j-1)/k,a[j+1]);
51         ans+=1LL*(j-1)/(k+1)*a[j];
52     }
53     printf("%lld\n",ans);
54     return 0;
55 }
View Code

 

posted @ 2020-12-01 17:08  DeepJay  阅读(162)  评论(0编辑  收藏  举报