缺席的神官,优化

「古时有一个懒惰的祭司,而祭司在连续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;
}

做这道题的时候,被这个求和的卡了好长时间,最后不得已才标记隔板,看了题解才发现原来这样也可以,还需进步,加油!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值