Codeforces Round 923 (Div. 3) 比赛记录

Codeforces Round 923 (Div. 3)
这是我第二次参加 cf阴间场。

10 minutes ago:

这次报名人数超过 4 万,一开始网站就崩溃了,比赛延迟了 10 分钟。。开局不顺。

2 minutes later:

cf成功地又炸了。过了 2 分钟,终于进去了。

A题

题目:
您有一个由 n 个单元格组成的水平条带。每个单元格要么是白色,要么是黑色。

您可以选择一段连续的单元格,然后将它们全部涂成白色。完成此操作后,该段中的所有黑色单元格将变为白色,而白色单元格将保持白色。

为了使所有 n 个单元格都变成白色,需要涂成白色的单元格段的最小长度是多少?
做法:模拟。
找到第一个出现和最后出现的黑色,下标相减再加 1 即可。

5 minutes later:

A题过

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll T,n,l1,l2;
string s;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n>>s;
		for(int i=0;i<n;i++)
			if(s[i]=='B'){l1=i;break;}
		for(int i=n-1;i>=0;i--)
			if(s[i]=='B'){l2=i;break;}
		cout<<l2-l1+1<<"\n";
    }
	return 0;
}

B题

题目:
波利卡普丢失了由小写拉丁字母组成的长度为 n 的字符串 s ,但他仍然保留着它的痕迹。

字符串 s 的踪迹是一个由 n 个整数组成的数组 a,其中 ai 是 si=sj 的索引 j (j < i) 的个数。例如,字符串 abracadabra 的踪迹是数组 [0,0,0,1,0,2,0,3,1,1,4]。

给定一个字符串的踪迹,从中找出个字符串 s。字符串 s 应该只由小写拉丁字母 a-z 组成。
做法:
用 vector 存字母出现次数对应的字母。
循环时每次取该次数减 1 时可以取到的字母,再存入即可。

15 minutes later:

B题过

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+10;
ll T,n,a[N];
char c,tt;
vector<char> p[N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i],p[i].clear();
		c='a';
		for(int i=1;i<=n;i++){
			if(!a[i]) cout<<(char)(c++),tt=c-1;
			else{
				ll t=p[a[i]-1].size();
				cout<<p[a[i]-1][t-1];
				tt=p[a[i]-1][t-1];
				p[a[i]-1].pop_back();
			}
			p[a[i]].push_back(tt);
		}
		cout<<"\n";
    }
	return 0;
}

C题

题目:
给定一个由 n 个整数组成的数组 a,一个由 m 个整数组成的数组 b 和一个偶数 k。

你的任务是确定是否有可能从这两个数组中选择的 k/2 个元素,使得所选元素中包括从 1 到 k 的每一个整数。

例如如果 a=[2,3,8,5,6,5],b=[1,3,4,10,5],k=6,那么可以从数组 a 中选择值为 2,3,6 的元素,从数组 b 中选择值为 1,4,5 的元素。在这种情况下,从 1 到 6 的所有数字都将包含在所选的元素中。

如果是 a=[2,3,4,5,6,5],b=[1,3,8,10,3],k=6,则无法按照要求选择元素。

请注意,您不需要找到选择元素的方法,您的程序只需检查是否可以按要求选择元素。
做法:
先判断两个数组中的数字是否包含了 1 到 k 的所有整数。
再判断两个数组是否分别拥有 k/2 个 1 到 k 的整数即可。

29 minutes later:

C题过

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+10;
ll T,n,m,k,ct1,ct2,a,b;
bool p[N],p1[N],p2[N];
bool flag;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n>>m>>k;
		flag=1;ct1=ct2=0;
		for(int i=1;i<=k;i++) p[i]=p1[i]=p2[i]=0;
		for(int i=1;i<=n;i++) cin>>a,p[a]=1,p1[a]=1;
		for(int i=1;i<=m;i++) cin>>b,p[b]=1,p2[b]=1;
		for(int i=1;i<=k;i++)
			if(!p[i]){flag=0;break;}
		for(int i=1;i<=k;i++)
			if(p1[i]) ct1++;
		for(int i=1;i<=k;i++)
			if(p2[i]) ct2++;
		if(ct1<k/2||ct2<k/2) flag=0;
		if(flag) cout<<"YES\n";
		else cout<<"NO\n";
    }
	return 0;
}

D题

题目:
给你一个由 n 个整数组成的数组 a 和 q 个查询。

对于每个查询,你都需要在 al,al+1,…,ar 中找到一对不同的元素,或者报告不存在这样一对元素。
做法:
贪心。
要找一对不同的元素,那么找最大值和最小值。
如果最大值和最小值不同,那么就存在。
st 表正可以。题目中 n 最大 1e5,st 表并不会超时。
预处理:O(nlogn) 查询:O(1)。
那么如何记录位置呢?
可以将 st 表记录的值改为下标,递推时再改一下即可。

100 minutes later:

st 表数组大小写反了。。
喜提3发罚时。
D题过

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+10;
ll T,n,q,l,r,A[N],f[33][N],g[33][N];
ll qrymin(ll l,ll r){
	ll k=log2(r-l+1);
	ll a=f[k][l],b=f[k][r-(1<<k)+1];
	return A[a]<A[b]?a:b;
}
ll qrymax(ll l,ll r){
	ll k=log2(r-l+1);
	ll a=g[k][l],b=g[k][r-(1<<k)+1];
	return A[a]>A[b]?a:b;
}
void st(){
	for(int i=1;i<=n;i++) f[0][i]=i,g[0][i]=i;
	for(int i=1;(1<<i)<=n;i++)
		for(int j=1;j+(1<<i)-1<=n;j++){
			ll l=f[i-1][j],r=f[i-1][j+(1<<i-1)];
			ll l2=g[i-1][j],r2=g[i-1][j+(1<<i-1)];
			f[i][j]=A[l]<A[r]?l:r; 
			g[i][j]=A[l2]>A[r2]?l2:r2; 
		}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>A[i];
		st();
		cin>>q;
		while(q--){
			cin>>l>>r;
			ll t1=qrymin(l,r),t2=qrymax(l,r);
			if(t1==t2||A[t1]==A[t2]) cout<<"-1 -1\n";
			else cout<<t1<<" "<<t2<<"\n";
		}
    }
	return 0;
}

E题

题目:
给你两个整数 n 和 k (k<n),其中 k 是偶数。

你的任务是构造一个长度为 n 的 k 级排列。

如果在所有长度为 k 的连续线段的总和中,任意两个和相差不超过 1,那么这个排列就叫做 k 级排列。

找出长度为 n 的任意一个 k 级排列。
做法:
构造题,考虑贪心。
将数组分为 n/k 组,且向上取整。
将数字从大到小填入数组中。
要使相差不超过 1,可以让较大的数与较小的数相邻。
因此每两次掉换循环方向。

赛后 9 分钟过。。
Deepl 的翻译出了问题,看题目看了好久,最后直接看的英文。。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+10;
ll T,n,k,ct,a[N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n>>k;ct=n;
		for(int i=1;i<=n;i++) a[i]=0;
		for(int i=1;ct;i++)
			if(i&1)
				for(int j=0;j<(n+k-1)/k;j++)
					if(j*k+i<=n) a[j*k+i]=(ct--);
			else
				for(int j=(n+k-1)/k-1;j>=0;j--)
					if(j*k+i<=n) a[j*k+i]=(ct--);
		for(int i=1;i<=n;i++) cout<<a[i]<<" ";
		cout<<"\n";
    }
	return 0;
}

n days later:

F题

题目:
给定一张 n 个点,m 条边,边有边权的无向图,无重边自环,不保证连通。定义一个简单环为不经过重复点与重复边的环路径,保证全图至少有一个简单环。记一个简单环的权值是环上最小的边权,你需要找到任意一个全图中权值最小的一个简单环并输出它。

3<=n,m<=2*10^5,w<=10^6。
做法:
考虑最小生成树的做法。

当这条边连接的点已经在同一个集合中时,就说明形成了环。

因此可以找出边的最小值。

之后找出这一条边所在的环即可。(dfs)
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=4e5+10;
ll T,n,m,t,ans,ct,h[N],a[N],f[N],fa[N];
struct E{
	ll u,v,w;
}e[N];
struct E2{
	ll to,nxt;
}e2[N];
void init(){
	for(int i=1;i<=n;i++) fa[i]=i,h[i]=f[i]=0;ct=t=ans=0;
}
bool cmp(E L,E R){
	return L.w>R.w;
}
ll getfa(ll x){
	return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
void add(E a){
	e2[++ct]={a.v,h[a.u]},h[a.u]=ct;
	e2[++ct]={a.u,h[a.v]},h[a.v]=ct;
}
void dfs(ll u,ll Fa){
	f[u]=Fa;
	for(int i=h[u];i;i=e2[i].nxt)
		if(e2[i].to!=Fa) dfs(e2[i].to,u);
}
void Ans(ll x,ll y){
	a[++ans]=x;
	if(x!=y) Ans(f[x],y);
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
		cin>>n>>m;
		for(int i=1;i<=m;i++) cin>>e[i].u>>e[i].v>>e[i].w;
		sort(e+1,e+m+1,cmp);init();
		for(int i=1;i<=m;i++){
			ll u=getfa(e[i].u),v=getfa(e[i].v);
			if(u==v) t=i;
			else fa[u]=v,add(e[i]);
		}
		cout<<e[t].w<<" ";
		dfs(e[t].u,0);Ans(e[t].v,e[t].u);
		cout<<ans<<"\n";
		for(int i=1;i<=ans;i++) cout<<a[i]<<" "; 
		cout<<"\n";
    }
	return 0;
}

G
没做,待更新~

总结:

  1. 数组范围不要开错。
  2. 不要依赖于翻译~
posted @ 2024-02-07 11:37  见合  阅读(56)  评论(0编辑  收藏  举报