Codeforces Round #802 (Div. 2) CD题解

C. Helping the Nature

题意:给定一个长度为 n n n 的数组。每次可以有以下三种操作:
①可以取一个数组下标 i ( 1 ≤ i ≤ n ) i(1\le i \le n) i(1in) ,然后让 [ 1 , i ] [1,i] [1,i] 的所有数减一;
②可以取一个数组下标 i ( 1 ≤ i ≤ n ) i(1\le i \le n) i(1in) ,然后让 [ i , n ] [i,n] [i,n] 的所有数减一;
③让整个数组所有数都加1。
问至少操作几次,可以使得整个数组所有元素为0。
思路:
1.整个区间同时加或减同一个数,可以想到用差分。将三个操作转化为对差分数组的三个操作:
a 1 a_1 a1 减一, a i + 1 a_{i+1} ai+1加1;
a i a_i ai 减一, a n + 1 a_{n+1} an+1加1;
a 1 a_1 a1 加一, a n + 1 a_{n+1} an+1减1。
可以看到对1号位置减一(同时不影响其他位置)的操作只有②,对1号位置加一(同时不影响其他位置)的操作只有③;对除1号位置减一的操作只有②,对除1号位置加一的操作只有①。操作的方式是唯一的。
2.要让整个数组所有元素变为0,等价于让原数组的差分数组所有元素变为0。
代码:

#include <bits/stdc++.h>
using namespace std;
 
#define il inline
#define pb push_back
#define fi first
#define se second
#define int long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=1e-6;
const int mod=1e7+7;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
 
int T,n,a[N],c[N];
 
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>T;
//	T=1;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;++i) cin>>a[i];
		for(int i=1;i<=n;++i) c[i]=a[i]-a[i-1];
		int ans=0;
		for(int i=2;i<=n;++i){
			if(c[i]<0) {
				ans-=c[i];
				c[1]+=c[i];
			}
			else ans+=c[i];
		}
		ans+=abs(c[1]);
		cout<<ans<<'\n';
	}
} 

D. River Locks

题意:给定一个长度为 n n n 的序列,每一个位置的值 a i a_i ai 代表第 i i i 个位置的水槽的体积,每个水槽正上方有一个泵,打开泵可以向水槽注水,第 i i i 个水槽满了,多出的水会流向第 i + 1 i+1 i+1 个水槽里,第 i + 1 i+1 i+1 个水槽满了,多出的水会流向第 i + 2 i+2 i+2 个水槽,以此类推,当第 n n n 个水槽满了,多出的水就流向河流,即浪费了。有 q q q 次询问,每次询问给定一个一个时间 t t t,问要在 t t t 时间内灌满所有水槽,至少需要开多少个泵,如果 t t t 时间内不可灌满所有水槽,输出-1。
思路:
1.优先选择上游的泵,这样多出来的水会流向后面的水槽。
2.对于每次询问给定的 t t t 。首先,显然,需要的泵的数量= ⌈ s u m t ⌉ \left \lceil \frac{sum}{t} \right \rceil tsum, s u m sum sum n n n 个水槽总体积,即,需要 ⌈ s u m t ⌉ \left \lceil \frac{sum}{t} \right \rceil tsum 个泵,这样才能在 t t t 时间内流到 s u m sum sum 体积水,但有了 ⌈ s u m t ⌉ \left \lceil \frac{sum}{t} \right \rceil tsum 个泵,不一定就能在 t t t 时间内灌满水槽,还要考虑一个时间下界,比如样例: 4 4 4 个水槽的体积分别为 6 , 1 , 1 , 1 6,1,1,1 6,1,1,1,给定时间 t = 5 t=5 t=5。这个下界应该是: max ⁡ k = 1 ∼ n ⌈ ∑ i = 1 k a i k ⌉ \max_{k=1\sim n} \left \lceil \frac{\sum_{i=1}^{k}a_i}{k} \right \rceil maxk=1nki=1kai
代码:

#include <bits/stdc++.h>
using namespace std;
 
#define il inline
#define pb push_back
#define fi first
#define se second
#define int long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=1e-6;
const int mod=1e7+7;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
 
int T,n,q;
 
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cin>>T;
	T=1;
	while(T--){
		cin>>n;
		int sum=0;
		int t,tt;
		int mx=0; //处理出最少需要的时间 
		for(int i=1;i<=n;++i){
			cin>>t;
			sum+=t;
			tt=ceil(sum*1.0/i);
			mx=max(tt,mx);
		}
		cin>>q;
		int cnt;
		while(q--){
			cin>>t;
			cnt=ceil(sum*1.0/t);
			if(cnt>n) cout<<-1<<'\n'; //需要大于n个泵的肯定不行 
			else { //如果需要的泵<=cnt,只有在t>=mx时,才可以。 
				if(t>=mx) cout<<cnt<<'\n';
				else cout<<-1<<'\n';
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值