[CF补题计划DAY4]Educational Codeforces Round 126 (Rated for Div. 2) A~D

2022.8.3 update:学会了线段树,更新D

碎碎念

昨天emo了又鸽了,后来发现心情不好只是因为忘记吃饭了,一顿夜宵解千愁
D怎么又是线段树啊,不活啦
不学线段树不行了呜呜

A.Array Balancing

第一发Wa了,考虑了后效性(?
实际根本不需要考虑,直接遍历判断,如果交换后a和b当前位与前一位的绝对值差的和更优则直接swap
后来想想把当前位与后一位的绝对值差考虑进去确实是假了,因为按照从左往右遍历的顺序,在考虑当前位时后一位是否会进行交换还不可知,贸然计算就会假。

B. Getting Zero

在校赛上做过类似的BFS,T了一发后发现有大量重复数据
单开一个ans数组记录已经知道的答案,如果输入的数字的答案已经可知,直接输出答案就行。

C. Water the Trees

首先可以确定树是不能长矮的,记mx为最高树高度,在最优地浇过水使所有树高度相同后,所有树的高度只可能是mx或mx+1。
如果是mx+2,就说明最高的树多浇了一个偶数天,相应的其他的树也要多浇一个偶数天,则不浇更优。
二分天数跑两遍,check函数里先判断至少需要奇数天的数量是否满足条件,再判断总需水量是否满足条件。

D. Progressions Covering

题意大概是给出一个b数组,每次操作选取长度为k的子段,使得

\(b[i]-=1,b[i+1]-=2,b[i+2]-=3...... b[i+k-1]-=k \ \ \ (i+k-1<=n)\)

问至少多少次可以使b的所有元素均小于等于0。

可以转化成维护一个差分序列,这样上述的操作就转化为区间\([i,i+k-1]\)每个数都减1,查询b的当前值转化为查询差分数组[1,i]的前缀和。
相对靠后的位置每次操作减去的值相对较大,因此可以从后往前考虑,判断这一位是否已经被减到小于等于0,若没有则执行区间减操作。

以前的我好懒啊怎么连代码都不贴……

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+100;
struct seg{
	int l,r,sum;
	int add;
}t[N*4];
int n,k,b[N];
inline void pushup(int p)
{
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;	
} 

inline void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r){t[p].sum=b[r]-b[r-1];return;}
	int mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);	
}

inline void pushdown(int p)
{
	if(t[p].add)
	{
		t[p<<1].sum+=t[p].add*(t[p<<1].r-t[p<<1].l+1);
		t[p<<1|1].sum+=t[p].add*(t[p<<1|1].r-t[p<<1|1].l+1);
		t[p<<1].add+=t[p].add;
		t[p<<1|1].add+=t[p].add;
		t[p].add=0;
	}
}

inline void change(int p,int l,int r,int k)
{
	if(l<=t[p].l&&r>=t[p].r) 
	{
		t[p].sum+=k*(t[p].r-t[p].l+1);
		t[p].add+=k;
		return;
	}
	pushdown(p);
	int mid=t[p].l+t[p].r>>1;
	if(l<=mid) change(p<<1,l,r,k);
	if(r>mid) change(p<<1|1,l,r,k);
	pushup(p);
}

inline int ask(int p,int l,int r)
{
	if(t[p].l>=l&&t[p].r<=r) {return t[p].sum;}
	pushdown(p);
	int mid=t[p].l+t[p].r>>1;
	int val=0;
	if(l<=mid) val+=ask(p<<1,l,r);
	if(r>mid) val+=ask(p<<1|1,l,r);
	return val;
}

main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>b[i];
	int res=0;
	build(1,1,n);
	for(int i=n;i;i--)
	{
		int x=ask(1,1,i);
		if(x<=0) continue;
		int now=min(i,k);
		int time=x/now+(x%now!=0);
		res+=time;
		change(1,i-now+1,i,-time);
		
	}
	cout<<res<<"\n";
}
posted @ 2022-04-30 18:23  Hssliu  阅读(32)  评论(0)    收藏  举报