Atcoder Beginner Contest 423 A-E

A

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int x,c;
int main(){
	read(x),read(c);
	int ans=x/(1+c*1.0/1000);
	printf("%d",ans/1000*1000);
	return 0;
}
//^o^

B

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n;
int a[maxn];
int main(){
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	int l=0,r=n+1;
	while(l<=n&&a[++l]==0);
	while(r>0&&a[--r]==0);
	if(l>r) printf("0");
	else printf("%d",r-l);
	return 0;
}
//^o^

C

也是简单的一道题,但是由于着急\(A\)掉,首 \(wa\) 以后尝试乱改 \(AC\)

于是————

image

告诫我们不能着急

image

大致结构是这样的,想必大家在 \(B\) 中有所了解

如果他在第 \(i\) 个房间,那么他就在 \(i\)\(i+1\) 号门之间

如果发现此时左边全是锁上的门,就不用继续向左处理门,右边同理

否则他所需要操作门的区间内,每个开着的门要操作两次,关着的门操作一次

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n,x;
int a[maxn];
int main(){
	read(n),read(x);
	for(int i=0;i<n;i++) read(a[i]);
	int ans=0;
	int l=0,r=n;
	while(a[l]&&l<x) ++l;
	while(a[r-1]&&r>x) --r;
	for(int i=l;i<r;i++) ans+=a[i]+1;
	printf("%d",ans);
	return 0;
}
//^o^

D

每一个团进入餐厅时,会产生一个截止时间点,其他团进入餐厅肯定会在这些时间点上

考虑把所有时间点都放到优先队列中,一个一个处理即可

CODE

注:代码中将值变为负数是为了直接适配小根堆,避免定义结构体或重载运算符

#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=3e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int a[maxn],b[maxn],c[maxn];
LL ans[maxn];
priority_queue<pair<LL,pii> > p;
int n,k;
int main(){
	read(n),read(k);
	for(int i=1;i<=n;i++){
		read(a[i]),read(b[i]),read(c[i]);
		p.push(mkp(-a[i],mkp(-c[i],i)));
	}
	queue<int> l;
	LL sum=0;
	while(!p.empty()){
		pair<LL,pii> i=p.top();
		p.pop(),i.fst=-i.fst,i.sec.fst=-i.sec.fst;
		if(i.sec.fst<0) sum+=i.sec.fst;
		else l.push(i.sec.sec);
		while((!l.empty())&&sum+c[l.front()]<=k){
			int j=l.front();
			l.pop(),sum+=c[j],ans[j]=i.fst;
			p.push(mkp(-(i.fst+b[j]),mkp(c[j],j)));
		}
	}
	for(int i=1;i<=n;i++){
		printf("%lld\n",ans[i]);
	}
	return 0;
}
//^o^

E

提供一种线段树做法,下面有官解写法

考虑如何计算合并两个区间所产生的新价值

image

如图,假设现将区间 \(abc\) 与区间 \(d\) 合并,新的价值中,每个数的系数分别是 \(1,2,3\)

同理,手推一下包含三个数的右边区间,每个数的系数分别是 \(3,2,1\)

怎么和并这样的阶梯状带权区间和呢?

image

如图,对于这样的由高到低的阶梯状系数和,其中 \(k\) 表示区间的阶梯状系数和,\(sum\) 表示区间和,\(p\) 表示区间包含的数字数量

得出 \(k[u]=k[l]+p[r]*sum[l]+k[r]\)

由于要一个系数由高到低,一个系数由低到高的带权区间和,所以分别表示为 \(k1,k2\)

则合并一个区间的价值为 \(t[u]=k1[l]*p[r]+k2[r]*p[l]+t[l]+t[r]\)

这样就有了区间和并操作,这样线段树就可以实现了,时间复杂度为 \(O(q\,\,log\,\,n)\)

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
struct node{
	LL t,sum;
	int p;
	LL k1,k2;
};
int n,q;
int a[maxn];
LL t[maxn<<2];
LL sum[maxn<<2];
LL k1[maxn<<2],k2[maxn<<2];
int p[maxn<<2];
void push_up(int u){
	sum[u]=sum[u<<1]+sum[u<<1|1];
	k1[u]=k1[u<<1]+p[u<<1]*sum[u<<1|1]+k1[u<<1|1];
	k2[u]=k2[u<<1]+p[u<<1|1]*sum[u<<1]+k2[u<<1|1];
	t[u]=k1[u<<1]*p[u<<1|1]+k2[u<<1|1]*p[u<<1]+t[u<<1]+t[u<<1|1];
	p[u]=p[u<<1]+p[u<<1|1];
}
void build(int l=1,int r=n,int u=1){
	if(l==r){
		p[u]=1;
		sum[u]=t[u]=k1[u]=k2[u]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,u<<1),build(mid+1,r,u<<1|1);
	push_up(u);
}
node query(int L,int R,int l=1,int r=n,int u=1){
	if(l>R||r<L) return (node){0,0,0,0,0};
	if(l>=L&&r<=R) return (node){t[u],sum[u],p[u],k1[u],k2[u]};
	int mid=(l+r)>>1;
	node a=query(L,R,l,mid,u<<1),b=query(L,R,mid+1,r,u<<1|1);
	return (node){a.k1*b.p+b.k2*a.p+a.t+b.t,a.sum+b.sum,a.p+b.p,a.k1+a.p*b.sum+b.k1,a.k2+b.p*a.sum+b.k2};
}
int main(){
	read(n),read(q);
	for(int i=1;i<=n;i++) read(a[i]);
	build();
	int l,r;
	while(q--){
		read(l),read(r);
		printf("%lld\n",query(l,r).t);
	}
	return 0;
}
//^o^

\(upd\,\,on\,\,2025.9.18\)

为了不造成误解,说一下官解做法

题目让我们求这个:

\[\sum _{i=l} ^r A_i(i-l+1)(r-i+1) \]

拆开来,整理一下:

\[\sum _{i=l} ^r \, [-A_i \times i^2 + (l+r) A_i \times i + (-lr+r-l+1) A_i] \]

然后提前做一下 \(A_i \times i^2 \,,\, A_i \times i \,,\, A_i\) 的前缀和即可

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=3e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int a[maxn],n,q;
LL s0[maxn],s1[maxn],s2[maxn];
int main(){
	read(n),read(q);
	for(int i=1;i<=n;i++){
		read(a[i]);
		s0[i]=s0[i-1]+a[i],s1[i]=s1[i-1]+a[i]*i,s2[i]=s2[i-1]+1ll*a[i]*i*i;
	}
	int l,r;
	while(q--){
		read(l),read(r);
		LL ans=-(s2[r]-s2[l-1])+1ll*(l+r)*(s1[r]-s1[l-1])+1ll*(r-l-1ll*l*r+1)*(s0[r]-s0[l-1]);
		printf("%lld\n",ans);
	}
	return 0;
}
//^o^
posted @ 2025-09-16 20:54  huangems  阅读(14)  评论(0)    收藏  举报