链接
题意
给出你 n n n个数, m m m次操作(可以不操作到m次防止出现负数),每次操作后将其加到 a n s ans ans中去,然后对这个数进行-1操作,问最大 a n s ans ans为多少.
分析
首先我们贪心想,肯定是先对大的数进行操作,那么我们对数组进行排序一次。这样我们直接从大的开始操作即可。
然后我们看 a [ n ] a[n] a[n] 到 a [ n − 1 ] a[n-1] a[n−1]我们看看他们直接的差 ( x = a [ n ] − a [ n − 1 ] ) (x=a[n]-a[n-1]) (x=a[n]−a[n−1])如果 x < = k x<=k x<=k 那么证明我们能直接从 a [ n ] a[n] a[n]操作到 a [ n − 1 ] a[n-1] a[n−1].贡献是 a [ n ] + a [ n − 1 ] + . . . + ( a [ n − 1 ] + 1 ) a[n]+a[n-1]+...+(a[n-1]+1) a[n]+a[n−1]+...+(a[n−1]+1)。代价是 ( x ) (x) (x).
然后我们递推到普遍情况:
a
[
i
]
a[i]
a[i]到
a
[
i
−
1
]
a[i-1]
a[i−1]这样一共有
n
−
i
+
1
n-i+1
n−i+1个a[i],要将其都变成
a
[
i
−
1
]
a[i-1]
a[i−1]花费的代价是
(
n
−
i
+
1
)
∗
x
(n-i+1)*x
(n−i+1)∗x,
(
x
=
a
[
i
]
−
a
[
i
−
1
]
)
(x=a[i]-a[i-1])
(x=a[i]−a[i−1]),贡献是
n
−
i
+
1
n-i+1
n−i+1个
(
a
[
i
]
+
a
[
i
]
−
1
+
.
.
.
+
(
a
[
i
−
1
]
+
1
)
)
(a[i]+a[i]-1+...+(a[i-1]+1))
(a[i]+a[i]−1+...+(a[i−1]+1))这个我们可以用等差序列的前n项和来解决。
那退出条件那,也就是边界值,分为两种:
- 都变成0了,我们不能加负数(这样会让其减少)
- 如果k<x,这样我们就不能将 ( n − i + 1 ) (n-i+1) (n−i+1)个 a [ i ] a[i] a[i]全部转化成 a [ i − 1 ] a[i-1] a[i−1],那么我们选优肯定是,先对大数进行操作,那么我们用 l = k / ( n − i + 1 ) l=k/(n-i+1) l=k/(n−i+1)这是我们可以整体移动的次数, r = k % ( n − i + 1 ) r=k\%(n-i+1) r=k%(n−i+1)这是单独的操作.贡献计算方法是这样的 整体移动我们可以直接用前缀和来维护,单独操作,我们是对 a [ i ] − l a[i]-l a[i]−l操作 r r r次,贡献就是 r ∗ ( a [ i ] − l ) r*(a[i]-l) r∗(a[i]−l)这样就是全部贡献。
// Problem: E - Amusement Park
// Contest: AtCoder - AtCoder Beginner Contest 216
// URL: https://atcoder.jp/contests/abc216/tasks/abc216_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
#define x first
#define y second
#define sf scanf
#define pf printf
#define PI acos(-1)
#define inf 0x3f3f3f3f
#define lowbit(x) ((-x)&x)
#define mem(a,x) memset(a,x,sizeof(a))
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
#define debug(x) cout << #x << ": " << x << endl;
const int MOD = 998244353;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int dx[] = {0, 1, -1, 0, 0};
const int dy[] = {0, 0, 0, 1, -1};
const int dz[] = {1, -1, 0, 0, 0, 0 };
int day[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
void init(){
}
ll n,k;
ll a[maxn];
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n);
ll ans=0;
a[0]=0;
for(int i=n;i>=1;i--){
ll cha=(a[i]-a[i-1]);
if(cha){
ll num=(n-i+1);
if(k>=num*cha){
k-=num*cha;
ans+=num*(cha*(a[i-1]+1)+(cha-1)*(cha)/2);
//cout<<ans<<endl;
}else {
ll l=k/num;
ll r=k%num;
ans+=num*(l*a[i]-(l-1)*(l)/2);
ans+=r*(a[i]-l);
break;
}
}
}
cout<<ans<<endl;
}
int main()
{
init();
ll t = 1;
//scanf("%lld",&t);
while(t--)
{
solve();
}
return 0;
}