P1672 [USACO05FEB] Feed Accounting S 题解

发布时间 2023-07-10 17:11:30作者: FHenryh

题目大意

题目传送门

简单翻译一下:给 \(c\) 个区间表示牛吃草的时间段,每头牛每天吃 \(1\) 千克,问距今天(即运来饲料 \(f_2\) 千克的时间)最近的送饲料 \(f_1\) 千克的时间是什么时候?

思路

初步思路

我们设 \(a_i\) 代表第 \(i\) 天吃了几千块的饲料,那么对于每头牛的吃饲料的时间,则需要将 \(a_l\)\(a_r\) 均暴力 \(+1\),然后从 \(d\) 往前遍历 \(x\),若 \(\sum^{i=x}_{d}a_i=f_2-f_1\),则第 \(x\) 天就是答案。

优化

这种暴力的复杂度显然不够优秀。

我们再来会看一下刚刚的暴力思路:

向将 \(a_l\)\(a_r\)\(+1\) 这样的区间修改,我们易想到用差分来优化,于是的 \(a\) 数组可用 \(O(D)\) 求得。

在求答案时,求的 \(\sum^{i=x}_{d}a_i\) 不难看出就是 \(a\) 数组的后缀和,那么易想到利用前缀和的思想 \(O(1)\) 求得解。

  • 时间复杂度 \(O(C+D)\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+1;
int c,d,f1,f2;
int dif[N];//差分
int a[N];
int sum[N];//后缀和
int main(){
	cin>>c>>f1>>f2>>d;
	int f=f1-f2;
	for(int i=1;i<=c;i++){
		int l,r;
		cin>>l>>r;
		dif[l]++;
		dif[r+1]--;//差分进行区间修改
	}
	for(int i=1;i<=d;i++)a[i]=a[i-1]+dif[i];
	for(int i=d;i>=1;i--){
		sum[i]=sum[i+1]+a[i];
		if(sum[i]==f){
			cout<<i;
			break;
		}
	}
	return 0;
}