「古时有一个懒惰的祭司,而祭司在连续m 天内必须一直去神庙内工作,但祭司的怠惰在诱惑着祭司,于是祭司决定这段时间内只选出k 个连续的时间段去神庙工作,但是高级祭司(祭司的上级)又会定期对神庙内的工作人员进行点名。祭司不想因此失去这份工作,所以提前知道了高级祭司会点名n 次以及每次点名的日子。所以祭司把点名的日子纳入工作的日子当中的同时又尽可能的偷懒。那么,这个祭司到底工作了多少天呢」
Input
第一行输入三个整数n,m,k
(1≤n≤2000) (n≤m≤109) (1≤k≤n),分别为高级祭司的点名次数,原本需要工作的天数和懒惰的祭司的工作次数。
第二行输入n 个数字ai (1≤ai≤m),为高级祭司检查的日期。
输入保证对于任意的i,j (1≤i<j≤n),都有ai<aj
Output
输出懒惰的祭司进行工作的最少天数
Samples
Input Copy
4 100 2
20 30 75 80
Output
17
Hint
样例的2 段为[20,30],[75,80],进行工作的最少天数为:11+6=17
优化前代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,k,a[2001],f[2001];
struct T{
int id,a;
}b[2001];
int cmp(T x,T y){
return x.a>y.a;
}
long long sum;
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<n;i++){ //求前缀;
b[i].a=a[i+1]-a[i];
b[i].id=i;
}
sort(b+1,b+n,cmp);
for(int i=1;i<k;i++){
f[b[i].id]=1; //把相隔的位置标记;
}
int l=1; //开始的位置;
for(int i=1;i<=n;i++){
if(f[i]==1||i==n){ //碰到隔板或到最后;
sum+=a[i]-a[l]+1; //从结束到开始的位置上的值+1;
l=i+1; //更新开始的位置;
}
}
cout<<sum;
return 0;
}
优化:计算前缀的时候不把两个边界算进去,最后去掉(k-1)个最大的前缀和后,求剩余前缀和的和,再加上总个数n;
优化代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=2e3+10;
int n,k;
ll m;
ll s[maxn];
ll a[maxn];
int main(){
scanf("%d%lld%d",&n,&m,&k);
int x=0;
for(int i=1;i<=n;i++)
scanf("%lld",&s[i]);
for(int i=n;i>=2;i--){
a[i-1]=s[i]-s[i-1]-1; //75-80 76 77 78 79
++x;
}
sort(a+1,a+1+x);
ll sum=0;
for(int i=1;i<=x-k+1;i++) sum+=a[i];
sum+=n;
cout<<sum<<endl;
return 0;
}