【CF套题】Educational Codeforces Round 56 (Rated for Div. 2)

本文精选了多项算法竞赛题目,包括概率计算、字符串处理、贪心算法、图论、动态规划、数据结构等核心算法,通过实际代码解析,深入浅出地讲解了算法设计与实现技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目】
原题地址

A.Dice Rolling

只需要输出一种合法方案,且一定有解。显然输出 ⌊ n 2 ⌋ \lfloor \frac n 2 \rfloor 2n即可。

#include<bits/stdc++.h>
using namespace std;

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
#endif
	int T=read();
	while(T--)
	{
		int n=read();
		printf("%d\n",n/2);
	}

	return 0;
}

B.Letters Rearranging

不能构造出非回文串当且仅当所有字符一样,否则将字符排序输出即可。

#include<bits/stdc++.h>
using namespace std;

int n,cnt[30];
char s[10000];

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
#endif
	int T=read();
	while(T--)
	{
		scanf("%s",s);n=strlen(s);int flag=0;
		memset(cnt,0,sizeof(cnt));
		for(int i=0;i<n;++i)
		{
			int c=s[i]-'a';
			if(!cnt[c]) ++flag;
			++cnt[c];
		}
		if(flag==1) puts("-1");
		else 
		{
			sort(s,s+n);printf("%s\n",s);
		}
	}

	return 0;
}

C.Mishka and the Last Exam

只需要贪心构造 a a a数组即可,具体来说我们使前半部分的 a i a_i ai尽量小,且判断对应后半部分的 a a a是否满足单调性即可。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e6+10;
ll n,a[N],b[N];

ll read()
{
	ll ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=(ll)ret*10+(c^48),c=getchar();
	return ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
#endif
	n=read()/2;
	for(int i=1;i<=n;++i) b[i]=read();
	a[n*2+1]=(ll)1e18;
	for(int i=1;i<=n;++i) 
	{
		ll t=b[i]-a[i-1];
		if(t>a[2*n-i+2]) t=a[2*n-i+2];
		a[2*n-i+1]=t;a[i]=b[i]-t;
	}
	for(int i=1;i<=2*n;++i) printf("%lld ",a[i]);

	return 0;
}

D.Beautiful Graph

两端点和为奇数,则奇偶性不同。对整幅图黑白染色后将每一块方案乘起来即可。一块的方案计算显然。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=3e5+10,mod=998244353;
int n,m,tot,flag,cnt,ans;
int head[N],col[N],ct[N][2];

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

struct Tway{int v,nex;}e[N<<1];
void add(int u,int v)
{
	e[++tot]=(Tway){v,head[u]};head[u]=tot;
	e[++tot]=(Tway){u,head[v]};head[v]=tot;
}

void clear()
{
	tot=0;flag=1;cnt=0;ans=0;
	for(int i=0;i<=n+1;++i) 
		head[i]=ct[i][0]=ct[i][1]=0,col[i]=-1;
}

void dfs(int bl,int x,int fa,int dp)
{
	col[x]=dp;++ct[bl][dp];
	if(!flag) return;
	for(int i=head[x];i;i=e[i].nex)
	{
		int v=e[i].v;
		if(v==fa) continue;
		if(~col[v])
		{
			if(col[v]==col[x]){flag=0;return;}
			continue;
		}
		dfs(bl,v,x,dp^1);
	}
}

ll qpow(int x,int y)
{
	ll res=1;
	for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) res=(ll)res*x%mod;
	return res%mod;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("D.in","r",stdin);
	freopen("D.out","w",stdout);
#endif
	int T=read();
	while(T--)
	{
		n=read();m=read();clear();
		for(int i=1;i<=m;++i) add(read(),read());
		for(int i=1;i<=n;++i)
		{
			if(!~col[i]) ++cnt,dfs(cnt,i,0,0);
		}
		if(!flag){puts("0");continue;}
		ll ans=1;
		for(int i=1;i<=cnt;++i)
		{
			///printf("%d %d\n",ct[i][0],ct[i][1]);
			ll res=0;
			(res+=(ll)qpow(2,ct[i][0])+qpow(2,ct[i][1]))%=mod;
			ans=ans*res%mod;
		}
		ans%=mod;cout<<ans<<endl;
	}

	return 0;
}

E.Intersection of Permutations

由于两个数组都是一个排列,我们将两个数组进行映射后使得问题可以转化为二维数点问题。具体来说,由于只有 b b b数组会变动,我们记录 a a a中每个数出现的位置,令 p o s [ a [ i ] ] = i pos[a[i]]=i pos[a[i]]=i,那么 ( i , p o s [ b [ i ] ] ) (i,pos[b[i]]) (i,pos[b[i]])即为二维平面上一个点,查询相当于询问 横 坐 标 [ l 2 , r 2 ] 横坐标[l_2,r_2] [l2,r2],纵坐标 [ l 1 , r 1 ] [l_1,r_1] [l1,r1]的矩阵中有多少个点。具体意义显然,我们可以用树套树来解决这个问题。

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+10;
int n,m;
int a[N],b[N],pos[N],rt[N];

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

struct Segment
{
	int sz,w[N<<7],ls[N<<7],rs[N<<7];
	queue<int>q;
	void update(int &x,int l,int r,int p,int v)
	{
		if(!x){if(!q.empty()) x=q.front(),q.pop(); else x=++sz;} w[x]+=v;
		if(l==r) return;
		int mid=(l+r)>>1;
		if(p<=mid) update(ls[x],l,mid,p,v);
		else update(rs[x],mid+1,r,p,v);
		if(!w[x]) q.push(x),x=0;
	}
	int query(int x,int l,int r,int L,int R)
	{
		if(!x) return 0;
		if(L<=l && r<=R) return w[x];
		int mid=(l+r)>>1,res=0;
		if(L<=mid) res+=query(ls[x],l,mid,L,R);
		if(R>mid) res+=query(rs[x],mid+1,r,L,R);
		return res;
	}
}t;

struct BIT
{	
	#define lowbit(x) (x&(-x))
	void update(int x,int p,int v){for(;x<N;x+=lowbit(x))t.update(rt[x],1,n,p,v);}
	int query(int x,int l,int r)
	{
		int res=0;
		for(;x;x-=lowbit(x))res+=t.query(rt[x],1,n,l,r);
		return res;
	}
}bit;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("E.in","r",stdin);
	freopen("E.out","w",stdout);
#endif
	n=read();m=read();
	for(int i=1;i<=n;++i) a[i]=read(),pos[a[i]]=i;
	for(int i=1;i<=n;++i) b[i]=read();
	for(int i=1;i<=n;++i) bit.update(i,pos[b[i]],1);
	while(m--)
	{
		int opt=read();
		if(opt&1)
		{
			int l1=read(),r1=read(),l2=read(),r2=read();
			printf("%d\n",bit.query(r2,l1,r1)-bit.query(l2-1,l1,r1));
		}
		else
		{
			int x=read(),y=read();
			bit.update(x,pos[b[x]],-1);bit.update(y,pos[b[y]],-1);
			bit.update(x,pos[b[y]],1);bit.update(y,pos[b[x]],1);
			swap(b[x],b[y]);
		}
	}
	return 0;
}

F.Vasya and Array

F:考虑这样一个状态: f i , j f_{i,j} fi,j表示前 i i i个数,已经有 j j j段连续数字的方案数。我们考虑对于每个状态从哪些状态贡献过来,显然我们可以知道从第 i i i个位置往前是否能将连续的一段全部换成某个数字,因此我们只需要用一个前缀和来维护这个 DP \text{DP} DP即可。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod=998244353,N=1e5+10,M=105;
int n,K,m,ans;
int a[N],s[N][M],f[N][M],g[N][M];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("F.in","r",stdin);
	freopen("F.out","w",stdout);
#endif
	n=read();K=read();m=read();
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1;i<=K;++i) s[1][i]=1;
	for(int i=2;i<=n+1;++i) for(int j=1;j<=K;++j)
		if(!~a[i-1] || a[i-1]==j) s[i][j]=s[i-1][j]; else s[i][j]=i;
	f[1][0]=g[1][0]=1;
	for(int i=2;i<=n+1;++i)
	{
		for(int j=1;j<=K;++j)
		{
			int las=max(s[i][j]-1,i-m);
			f[i][j]=((ll)(g[i-1][0]-g[las][0]-(g[i-1][j]-g[las][j]))%mod+mod)%mod;
			g[i][j]=(g[i-1][j]+f[i][j])%mod;
			g[i][0]=(g[i][0]+f[i][j])%mod;
		}
		g[i][0]=(g[i-1][0]+g[i][0])%mod;
	}
	for(int i=1;i<=K;++i) (ans+=f[n+1][i])%=mod;
	printf("%d\n",ans);

	return 0;
}

G.Multidimensional Queries

考虑曼哈顿距离的计算方式,则两点之间大小坐标大小关系在去掉绝对值之后有 2 k 2^k 2k种方式,我们枚举这个关系,用线段树维护最大值即可。

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+10;
int n,k,K,Q,a[N][6];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

struct Segment
{
	#define ls (x<<1)
	#define rs (x<<1|1)
	int w[N<<2][32];
	void update(int x,int l,int r,int p)
	{
		if(l==r)
		{
			for(int i=0;i<1<<k-1;++i)
			{
				int t=0;
				for(int j=0;j<k;++j) t+=a[p][j]*((i&(1<<j))?-1:1);
				w[x][i]=t;w[x][K^i]=-t;
			}
			return;
		}
		int mid=(l+r)>>1;
		if(p<=mid) update(ls,l,mid,p);
		else update(rs,mid+1,r,p);
		for(int i=0;i<=K;++i) w[x][i]=max(w[ls][i],w[rs][i]);
	}
	int query(int x,int l,int r,int L,int R,int mask)
	{
		if(L<=l && r<=R) return w[x][mask];
		int mid=(l+r)>>1,res=-1e9;
		if(L<=mid) res=max(res,query(ls,l,mid,L,R,mask));
		if(R>mid) res=max(res,query(rs,mid+1,r,L,R,mask));
		return res;
	}
}tr;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("G.in","r",stdin);
	freopen("G.out","w",stdout);
#endif
	n=read();k=read();K=(1<<k)-1;
	for(int i=1;i<=n;++i) 
	{
		for(int j=0;j<k;++j) a[i][j]=read();
		tr.update(1,1,n,i);
	}
	Q=read();
	while(Q--)
	{
		int op=read();
		if(op&1)
		{
			int x=read();
			for(int i=0;i<k;++i) a[x][i]=read();
			tr.update(1,1,n,x);
		}
		else
		{
			int l=read(),r=read(),ans=0;
			for(int i=0;i<1<<k-1;++i) ans=max(ans,tr.query(1,1,n,l,r,i)+tr.query(1,1,n,l,r,K^i));
			printf("%d\n",ans);
		}
	}
	return 0;
}

【总结】
巨蒻无比。

"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问组成,选手需要根据给定的问描述和测试用例,编写程序来解决这些问。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值