ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Virt.Contest】CF1321(div.2)

2022-08-27 13:01:32  阅读:171  来源: 互联网

标签:CF1321 200005 int Virt ll long div.2 短路 dis


第一次打虚拟赛。

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有