ABC467 赛后总结

共 1230 字
11 分钟
0 次阅读

本场 Rating:$\textcolor{#00C0C0}{1591} \rightarrow \textcolor{#0000FF}{1668}(+77)$。

本场表现分:$\textcolor{#C0C000}{2155}$。


啊好想养一棵香香软软的线段树啊。


A Obesity

题目

嘻嘻,没想到吧,$100^2 = 10000$。

:::success[code]

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int main(){
	int h,w;
	scanf("%d%d",&h,&w);
	if(25*h*h<=10000*w)puts("Yes");
	else puts("No"); 
	return 0;
}

:::

B Keep the Change

题目

无。

:::success[code]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	int ans=0;
	for(int i=1;i<=n;i++){
		int a,b;
		string s;
		cin>>a>>b>>s;
		if(s=="keep")ans+=b-a;
	}
	printf("%d",ans);
	return 0;
}

:::

C Adjacent Sums (easy)

题目

枚举第一位,然后依次向后算。

:::success[code]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200005],b[200005];
int ta[200005],qa[200005];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	for(int j=1;j<n;j++)scanf("%d",b+j);
	int t1=a[1],t2=a[1]^1;
	ta[1]=0;
	for(int i=2;i<=n;i++){
		t1+=b[i-1]^ta[i-1]^a[i];
		ta[i]=b[i-1]^ta[i-1];
	}
	qa[1]=1;
	for(int i=2;i<=n;i++){
		t2+=b[i-1]^qa[i-1]^a[i];
		qa[i]=b[i-1]^qa[i-1];
	}
	printf("%d",min(t1,t2));
	return 0;
}

:::

D Concentric Circles

题目

注意到一个圆的圆心一定在其上任取两点的垂分线上。所以构成同心圆,要么是两条线不平行,要么是在同一直线上。

:::success[code]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<bits/stdc++.h>
using namespace std;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int px,py,qx,qy,rx,ry,sx,sy;
		scanf("%d%d%d%d%d%d%d%d",&px,&py,&qx,&qy,&rx,&ry,&sx,&sy);
		long long a[4];
		a[0]=px-qx;
		a[1]=py-qy;
		a[2]=rx-sx;
		a[3]=ry-sy;
		long long cross=a[0]*a[3]-a[1]*a[2];
		if(cross!=0)puts("Yes");
		else{
			long long d=a[2]*(1ll*px+qx-rx-sx)+a[3]*(1ll*py+qy-ry-sy);
			if(d==0)puts("Yes");
			else puts("No");
		}
	}
	return 0;
}

:::

E Adjacent Sums (hard)

题目

!?drahard?!

令每个位置的变化量为 $g_i$。

我们考虑对 $A_i + g_i + A_{i+1} + g_{i+1} \equiv B_i \pmod M$ 做变形,即:

$$g_i + g_{i+1} \equiv B_i - A_i - A_{i+1} \pmod M$$

令 $C_i = B_i - A_i - A_{i+1}$,则

$$ g_i + g_{i+1} \equiv C_i \pmod M$$

当确定了 $g_1$,剩下的每个数字都可以被唯一确定,即

$$g_{i+1} \equiv C_i - g_i \pmod M$$

递归下去,不难发现:

奇数位是一个 $k=1$ 的一次函数,并且在 $m-g_i$ 处 $-M$;

偶数位是一个 $k=-1$ 的一次函数,并且在 $g_i$ 处 $+M$。

又因为最优解肯定 $\in [0,M)$,因此维护每一个跳变点并计算解的值。

:::success[code]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200005],b[200005],c[200005],d[200005];
int main(){
	ll n,m;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",a+i);
	for(int i=1;i<n;i++)scanf("%lld",b+i);
	for(int i=1;i<n;i++)c[i]=(b[i]-a[i]-a[i+1]+m+m)%m;
	d[1]=0;
	for(int i=2;i<=n;i++)d[i]=(c[i-1]-d[i-1]+m)%m;
	vector<pair<ll,ll> > task;
	ll sl=0;
	ll s=0;
	for(int i=1;i<=n;i++){
		s+=d[i];
		if(i&1){
			sl++;
			if(d[i]!=0)task.push_back({m-d[i],-m});
		}else{
			sl--;
			if(d[i]!=m-1)task.push_back({d[i]+1,+m});
		}
	}
	sort(task.begin(),task.end());
	ll ans=s;
	ll lst=0;
	for(int i=0;i<task.size();i++){
		ll x=task[i].first;
		s+=(x-lst)*sl;
		while(i<task.size()&&task[i].first==x)s+=task[i++].second;
		i--;
		ans=min(ans,s);
		lst=x;
	}
	printf("%lld",ans);
	return 0;
}

:::

F Email Scheduling Optimization

题目

首先注意到最优解是按 $B_i$ 降序。证明?这不是板子吗。

:::info[证明(官方题解)]

Suppose that it is optimal to write to companies $P_1,P_2,\dots,P_N$, in this order.
Suppose $B_{P_i} \lt B_{P_{i+1}}$ for some $i$.
Let $S=\sum_{j=1}^{i-1}{A_{P_j}}$.
Swapping $P_i$ and $P_{i+1}$ makes the time receiving the email from company $P_i$ from $S+A_{P_i}+B_{P_i}$ to $S+A_{P_{i+1}}+A_{P_i}+B_{P_i}$,
and the time receiving the email from company $P_{i+1}$ from $S+A_{P_{i+1}}+B_{P_{i+1}}$.
$\max(S+A_{P_i}+B_{P_i},S+A_{P_i}+A_{P_{i+1}}+B_{P_{i+1}}) \ =S+A_{P_i}+A_{P_{i+1}}+B_{P_{i+1}}\ \gt \max(S+A_{P_{i+1}}+A_{P_i}+B_{P_i},S+A_{P_{i+1}}+B_{P_{i+1}}),$ so swapping them does not worsen the time required to receive all emails. We also see that, if $B_{P_i}=B_{P_{i+1}}$, then swapping $P_i$ and $P_{i+1}$ does not affect the time required. Hence, it is optimal to write emails in descending order of $B$.

:::

显然对于确定的 $A,B$ 序列,答案即 $max_{i=1}^n (\sum_{t=1}^k A_{p_t}) + B_{p_k}$。

区间最大值?

那么……

线!段!树!

但是由于 $B_i$ 可能很大,我们需要 对 998244353 取模 离散化。注意修改 $2$ 可能导致 $B$ 序列顺序变化,离散化的时候要提前留好位置。

现在考虑线段树每个节点都要维护的信息。

由于我们的计算公式,只需要维护一段区间内的元素和,以及答案。合并显然简单。

:::success[code]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
using namespace atcoder;
typedef long long ll;
struct ND{
	ll sum,maxv;
}; 
ND op(ND x,ND y){
	return {x.sum+y.sum,max(x.sum+y.maxv,x.maxv)}; 
}
ND e(){
	return {0,0};
}
int n,q,m;
int a[100005],b[100005];
bool cmp(pair<ll,int> a,pair<ll,int> b){
	if(a.first!=b.first)return a.first>b.first;
	return a.second>b.second;
}
struct QUERY{
	int op,i;
	ll x;
}que[100005];
vector<pair<ll,int> > ys;
int getpos(ll b,int id){
	ll t=lower_bound(ys.begin(),ys.end(),make_pair(b,id),greater<pair<ll,int> >())-ys.begin();
	return t;
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	for(int i=1;i<=n;i++)scanf("%d",b+i);
	for(int i=1;i<=n;i++)ys.push_back({b[i],i});
	for(int i=1;i<=q;i++){
		scanf("%d%d%lld",&que[i].op,&que[i].i,&que[i].x);
		if(que[i].op==2)ys.push_back({que[i].x,que[i].i});
	}
	sort(ys.begin(),ys.end(),cmp);
	ys.erase(unique(ys.begin(),ys.end()),ys.end());
	m=ys.size();
	//啊好像养一棵香香软软的线段树啊
	segtree<ND,op,e>seg(m);
	for(int i=1;i<=n;i++){
		int pos=getpos(b[i],i);
		seg.set(pos,{a[i],a[i]+b[i]});
	}
	for(int i=1;i<=q;i++){
		int qi=que[i].i;
		ll qx=que[i].x;
		if(que[i].op==1){
			a[qi]=qx;
			int pos=getpos(b[qi],qi);
			seg.set(pos,{a[qi],a[qi]+b[qi]});
		}else{
			int pos=getpos(b[qi],qi);
			seg.set(pos,e());
			b[qi]=qx;
			pos=getpos(b[qi],qi);
			seg.set(pos,{a[qi],a[qi]+b[qi]});
		}
		printf("%lld\n",seg.all_prod().maxv);
	}
	return 0;
}

:::

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计