cf 923 div3总结

Codeforces Round 923 (Div. 3)

这是我第二次参加 cf阴间场。

10 minutes ago:

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

2 minutes later:

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

A题:
题目:

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

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

为了使所有 n n n 个单元格都变成白色,需要涂成白色的单元格段的最小长度是多少?

做法:模拟。

找到第一个出现和最后出现的黑色,下标相减再加 1 1 1 即可。

5 minutes later:

A题过。

代码:

#include
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 n n 的字符串 s ,但他仍然保留着它的痕迹。

字符串 s s s 的踪迹是一个由 n n n 个整数组成的数组 a a a,其中 a i a_i ai s i = s j si=sj si=sj 的索引 j j j ( j < i j < i j<i) 的个数。

例如,字符串 abracadabra 的踪迹是数组 [ 0 , 0 , 0 , 1 , 0 , 2 , 0 , 3 , 1 , 1 , 4 ] [0,0,0,1,0,2,0,3,1,1,4] [0,0,0,1,0,2,0,3,1,1,4]

给定一个字符串的踪迹,从中找出个字符串 s s s。字符串 s s s 应该只由小写拉丁字母 a-z 组成。

做法:

vector 存字母出现次数对应的字母。

循环时每次取该次数减 1 时可以取到的字母,再存入即可。

15 minutes later:

B题过。

代码:

#include
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 n n 个整数组成的数组 a a a,一个由 m m m 个整数组成的数组 b b b 和一个偶数 k k k

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

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

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

请注意,您不需要找到选择元素的方法,您的程序只需检查是否可以按要求选择元素。

做法:

先判断两个数组中的数字是否包含了 1 1 1 k k k 的所有整数。

再判断两个数组是否分别拥有 k ÷ 2 k \div 2 k÷2 1 1 1 k k k 的整数即可。

29 minutes later:

C题过。

代码:

#include
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
D题
题目:

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

对于每个查询,你都需要在 a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r al,al+1,,ar 中找到一对不同的元素,或者报告不存在这样一对元素。

做法:

贪心。

要找一对不同的元素,那么找最大值和最小值。

如果最大值和最小值不同,那么就存在。

st 表正可以。题目中 n n n 最大 2 × 1 0 5 2 \times 10^5 2×105st 表并不会超时。

预处理:O(nlogn) 查询:O(1)。

那么如何记录位置呢?

可以将 st 表记录的值改为下标,递推时再改一下即可。

100 minutes later:

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

D题过

代码:

#include
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 n n k k k ( k < n kk<n),其中 k k k 是偶数。

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

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

找出长度为 n n n 的任意一个 k k k 级排列。

做法:

构造题,考虑贪心。

将数组分为 ⌊ n k ⌋ \left\lfloor\frac{n}{k}\right\rfloor kn 组,向上取整。

将数字从大到小填入数组中。

要使相差不超过 1,可以让较大的数与较小的数相邻。

因此每两次掉换循环方向。

赛后 9 分钟过。。

deepl 的翻译出了问题,看题目看了好久,最后直接看的英文。。

代码:

#include
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;
}

F
G
没做,待更新~

总结:

  1. 数组范围不要开错。
  2. 不要依赖于翻译~

你可能感兴趣的:(比赛总结,c++)