codeforces-Ed94-E

codeforces-Ed94-E

八月 28, 2020

E. Clear the Multiset

题意

给出一个数组a,长度为n<5000

对于一次操作有两种选择:

1.使a[L~R]-1

2.使a[i]-x

问最少几次操作得到全为0的数组

题解

对于一个局面,我们的操作顺序并不影响最终的答案

对于一个区间[L,R] 将其中的数全变为0,

要么只使用操作2,将L到R内的数逐个归0,共R-L+1次操作

要么找到区间内最小值minn,它在位置mpos

使用操作1将区间[L,R]都减去minn,递归求解[L,mpos-1]和[mpos+1,R]区间的子问题

则对于区间[L,R]的最小操作次数:

1
ans=min(minn+divid_conquer(L,mpos-1,minn)+divid_conquer(mpos+1,R,minn)-Min,R-L+1);

其中Min为上个区间中的最小值,即[L,R]的区间最小值记为Min

[L,mpos-1]的区间最小值为minn,且minn>=Min一定成立

对于递归边界当(L==R)是若data[L]-Min!=0则使用1次操作2 否则返回0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
const ll Max=5000+5;
const double Pi=acos(-1);
const ll Mod=1e9+7;
/*
*/
int data[Max];
ll divid_conquer(ll L,ll R,ll Min){
//cout<<L<<" "<<R<<" "<<Min<<endl;
if(L==R)return (data[L]-Min>0?1:0);
else if(L>R)return 0;
int minn=1e9+5,mpos=0;
for(int i=L;i<=R;i++){
if(minn>data[i]){
minn=data[i];
mpos=i;
}
}
ll ans=min(minn+divid_conquer(L,mpos-1,minn)+divid_conquer(mpos+1,R,minn)-Min,R-L+1);
return ans;
}
int main() {
Turnoff;
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>data[i];
ll ans=divid_conquer(1,n,0);
cout<<ans<<endl;
}