其他分享
首页 > 其他分享> > 【Virt.Contest】CF1321(div.2)

【Virt.Contest】CF1321(div.2)

作者:互联网

第一次打虚拟赛。

CF 传送门

T1:Contest for Robots

统计 \(r[i]=1\) 且 \(b[i]=0\) 的位数 \(t1\) 和 \(r[i]=0\) 且 \(b[i]=1\) 的位数 \(t2\)。

两个数都为 \(0\) 或都为 \(1\) 时没有贡献。

若 \(t1=0\),则 \(r\) 序列不管乘多大的 \(p\) 也不会比 \(b\)序列更大,所以直接输出 \(-1\)。

否则,我们考虑将 \(r[i]=0\) 且 \(b[i]=1\) 的位置的 \(p[i]\) 取 \(1\),总耗费 \(t2\),然后均摊到 \(r[i]=1\) 且 \(b[i]=0\) 的位数 \(t1\),显然最优。这时 \(p \max\) 即为 \(>\frac{t2}{t1}\) 的最小整数。

\(T1\) 还是比较水的,\(8min\) 切掉 \(qwq\)

Code:

#include<bits/stdc++.h>
using namespace std;
int n,a[105],b[105],T1,T2;
int main(){
	scanf("%d",&n);
	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++){
		if(a[i]==1&&b[i]==0) T1++;
		if(b[i]==1&&a[i]==0) T2++;
	}
	if(T1==0) printf("-1");
	else printf("%d",T2/T1+1);
    return 0;
}

T2:Journey Planning

看到了 \(c_{i+1}-c_i=b_{c_{i+1}}-b_{c_i}\),对着样例想了一会才发现应该移项。变成:

\(b_{c_{i+1}}-c_{i+1}=b_{c_i}-c_i\)

由此发现,一次旅行所经过的点应该满足其美丽值与其下标的差相同

所以想到用桶来存储差值。一开始脑抽,将要求 \(c_k>c_{k-1}\) 理解成了美丽值要递增,就想怎么还要分别做最大上升子序列,复杂度怎么都是不正确的。再看才发现是下标递增。这不直接把美丽值扔桶里算最大值就好了 \(qwq\)。

同时要注意,因为 \(b_{c_i}-c_i\) 可能为负值,不能直接做下标,所以将桶开大一些,以 \(n+b_{c_i}-c_i\) 做下标即可。

我才不会告诉你我没开 \(long\) \(long\) WA 了两发

较水,\(26min\) AC \(qwq\)

Code:

#include<bits/stdc++.h>
using namespace std;
long long n,a[200005],t[800005],ans;
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		int tmp=a[i]-i+n;
		t[tmp]+=a[i];
		ans=max(t[tmp],ans);
	}
	printf("%lld",ans);
    return 0;
}

T3:Remove Adjacent

贪心。可以想到从 \(z\) 删到 \(a\) 是最优的。

思路很快就有了。让 \(k\) 从 \(z\) 开始,将字符串一位一位匹配,如果 \(s_i=k\),就往左右两边找,直到找到一个没有被删的,若其中一个是 \(k-1\),则可以删掉第 \(i\) 位,给它赋个随便啥字符就好(如 '#')。最后看有几个 '#',就是答案。于是,就有了下面的错误代码

#include<bits/stdc++.h>
using namespace std;
string s,k="zyxwvutsrqponmlkjihgfedcba";
int ans,n;
int main(){
	scanf("%d",&n);
	cin>>s;
	for(int i=0;i<=25;i++){
		for(int j=0;j<n;j++){
			if(s[j]!=k[i]) continue;
			int l=max(j-1,0),r=min(j+1,n-1);
			if(j!=0){
				while(s[l]=='#'&&l>0) l--;
				if(s[j]-1==s[l]) s[j]='#';
			}
			if(j!=n-1){
				while(s[r]=='#'&&r<n-1) r++;
				if(s[j]-1==s[r]) s[j]='#';
			}
		}
	}
	for(int i=0;i<n;i++) if(s[i]=='#') ans++;
	printf("%d",ans);
    return 0;
}

Then:

当时:test10 是个什么牛马*** 哪里出问题了呢?

于是手胡了几个数据,终于发现了错误:

10
yyyyxyyyyy

正确答案显然是 \(9\),因为所有 \(y\) 都可以被删掉。

但我的程序就输出 \(6\) 了。因为,对每个字母我只从左往右扫了一遍,所以前三个 \(y\) 被跳过之后就再也不管了 \(qwq\)。

所以,只要在每次删除后把 \(j\) 跳回 \(-1\) 就好了,从头再扫。由于 \(s\) 长度只有 \(100\) ,所以复杂度完全没问题。

最后,\(51min\) AC \(qwq\)

Code:

#include<bits/stdc++.h>
using namespace std;
string s,k="zyxwvutsrqponmlkjihgfedcba";
int ans,n;
int main(){
	scanf("%d",&n);
	cin>>s;
	for(int i=0;i<=25;i++){
		for(int j=0;j<n;j++){
			if(s[j]!=k[i]) continue;
			int l=max(j-1,0),r=min(j+1,n-1);
			if(j!=0){
				while(s[l]=='#'&&l>0) l--;
				if(s[j]-1==s[l]) s[j]='#',j=-1;
			}
			if(j!=n-1){
				while(s[r]=='#'&&r<n-1) r++;
				if(s[j]-1==s[r]) s[j]='#',j=-1;
			}
		}
	}
	for(int i=0;i<n;i++) if(s[i]=='#') ans++;
	printf("%d",ans);
    return 0;
}

T4:Navigation System

看到最短路就懵。

一眼 \(Dijkstra\),但我还不会写板子。赛时套版固然不好,所以就先放着了,直接去看 \(T5\)、\(T6\)。然后也都没思路,就回来了。

思路:对于给出的路径 \(p\):

若当前所走到的 \(p_i\) 在唯一最短路,则不用变。

若当前所走到的 \(p_i\) 在最短路,但不唯一,则最多重构次数 \(+1\),因为导航可能给你导了另外一条最短路。

若当前所走到的 \(p_i\) 不在最短路,则最多重构次数、最少重构次数都 \(+1\),因为导航一定给你导了当前最短路,必须重置。

所以只要以终点 \(p_k\) 为起点,建一张反图,然后跑单源最短路即可。

看来要练最短路了

赛后代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,ans,ex,x,y;
int head[200005],rhead[200005],tot,rtot;
struct node{
	int nxt,to;
}e[200005],re[200005];
int k,p[200005],t,s,dis[200005];
queue<int> q;
void add(int from,int to){
	tot++;
	e[tot].to=to;
	e[tot].nxt=head[from];
	head[from]=tot;
}
void radd(int from,int to){
	rtot++;
	re[rtot].to=to;
	re[rtot].nxt=rhead[from];
	rhead[from]=rtot;
}
void bfs(){
	q.push(t);
	memset(dis,0x3f,sizeof(dis));
	dis[t]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=rhead[u];i;i=re[i].nxt){
			int v=re[i].to;
			if(dis[v]==0x3f3f3f3f){
				dis[v]=dis[u]+1;
				q.push(v);
			}
 		}
	}
	return ;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&x,&y);
		add(x,y);
		radd(y,x);
	}
	scanf("%d",&k);
	for(int i=1;i<=k;++i) scanf("%d",&p[i]);
	s=p[1],t=p[k];
	bfs();
	for(int i=1;i<k;i++){
		int u=p[i];
		if(dis[p[i+1]]+1!=dis[p[i]]) ans++;
		else{
			for(int j=head[u];j;j=e[j].nxt){
				int v=e[j].to;
				if(v==p[i+1]) continue;
				if(dis[v]==dis[p[i+1]]){
					ex++;
					break;
				}
			}
		}
	}
	printf("%d %d",ans,ans+ex);
    return 0;
}

T5:World of Darkraft: Battle for Azathoth

首先,将武器按照攻击力从小到大排序,防具按照防御力从小到大排序,怪物按照防御力从小到大排序,然后将武器从左往右扫,可以知道武器 \(i\) 能打的怪物武器 \(i+1\) 也能打,所以能打的怪物个数是单调上升的。所以每次就将武器 \(i+1\) 比武器 \(i\) 多打的怪物加入集合中,然后维护防具 \(x\) 能在当前怪物集合中得到的利益。

显然对于能防御怪物 \(x\) 的防具连续的一段区间(因为排了序呀),于是就可以二分查找第一个严格大于怪物 \(x\) 的防御力的防具,然后区间加,再查找全局最大值就好了。

至于维护防具的数据结构,肯定线段树呀。

——来自 \(\color{red}{Silver187}\) 巨佬的 题解

记得线段树空间开 \(4\) 倍大!

Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,p,k=1;
ll d[200005],ans=-1e16;
struct node1{ll x,y;}a[200005],b[200005];
struct node2{ll x,y,z;}c[200005];
struct tree{
	int l,r;
	ll dat,add;
}t[800005];
bool cmp1(node1 a,node1 b){return a.x<b.x;}
bool cmp2(node2 a,node2 b){return a.x<b.x;}
void build(int p,int l,int r){
	t[p].l=l,t[p].r=r;
	if(l==r){
		t[p].dat=-b[l].y;
		return ;
	}
	int md=(l+r)/2;
	build(p*2,l,md);
	build(p*2+1,md+1,r);
	t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void _updata(int p){
	if(t[p].add){
		t[p*2].add+=t[p].add;
		t[p*2+1].add+=t[p].add;
		t[p*2].dat+=t[p].add;
		t[p*2+1].dat+=t[p].add;
		t[p].add=0;
	}
}
void _change(int p,int l,int r,ll d){
	if(l<=t[p].l&&r>=t[p].r){
		t[p].add+=d;
		t[p].dat+=d;
		return ;
	}
	_updata(p);
	int md=(t[p].l+t[p].r)/2;
	if(l<=md) _change(p*2,l,r,d);
	if(r>md) _change(p*2+1,l,r,d);
	t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
ll q_max(int p,int l,int r){
	if(l<=t[p].l&&r<=t[p].r) return t[p].dat;
	_updata(p);
	int md=(t[p].l+t[p].r)/2;
	ll v=-1e16;
	if(l<=md) v=max(v,q_max(p*2,l,r));
	if(r>md) v=max(v,q_max(p*2+1,l,r));
	return v;
}
void _add(int k){
	int tmp=upper_bound(d+1,d+m+1,c[k].y)-d;
	if(tmp<=m) _change(1,tmp,m,c[k].z);
}
int main(){
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	for(int i=1;i<=m;i++) scanf("%d%d",&b[i].x,&b[i].y);
	for(int i=1;i<=p;i++) scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].z);
	sort(a+1,a+n+1,cmp1);
	sort(b+1,b+m+1,cmp1);
	sort(c+1,c+p+1,cmp2);
	for(int i=1;i<=m;i++) d[i]=b[i].x;
	build(1,1,m);
	for(int i=1;i<=n;i++){
		while(k<=p&&c[k].x<a[i].x) _add(k),k++;
		ans=max(ans,q_max(1,1,m)-a[i].y);
	}
	printf("%lld",ans);
    return 0;
}

T6:Reachable Strings

施工中 \(qwq\)

标签:CF1321,200005,int,Virt,ll,long,div.2,短路,dis
来源: https://www.cnblogs.com/binary1110011/p/16630374.html