Educational Codeforces Round 150 (Rated for Div. 2) A-E

[比赛链接](Dashboard - Educational Codeforces Round 150 (Rated for Div. 2) - Codeforces)

A.Game with Board

n>=5先手赢,否则后手赢

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n,m; 
int a[500005];
void solve(){
scanf("%lld",&n);
if(n>=5)printf("Alice\n");
else printf("Bob\n");
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}

B.Keep it Beautiful

当一个序列可以拆分成两段非递减序列,且第二段非递减序列的结尾要大于第一段的开头则这个序列是“美丽的”,维护这个过程,当第一次(出现递减且小于等于第一个数时),把这个数当作第二段非递减数的开头,后面的数要满足大于当前队尾且小于等于第一个数。

所以答案为1的数是,第一段非递减序列和第二段非递减序列,其它答案为0

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n;
int t;
void solve(){
int now=0;
int ok=-1;
scanf("%lld",&n);
int fir=-1;
for(int i=1;i<=n;i++){
	scanf("%lld",&t);
	if(i==1)fir=t;
	if(t>=now){
		
		if(ok==-1){
		printf("1");
		now=t;}
		else{
			if(t<=fir){
				printf("1");
				now=t;
			}
			else{
				printf("0");
			}
		}
	}
	else{
		if(ok==-1&&t<=fir){
			ok=1;
			printf("1");
			now=t;
		}
		else{
			printf("0");
		}
	}
}
printf("\n");
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}

C.Ranom Numbers

大模拟,先处理一个后缀字母最大值,以及后缀在没有修改的条件下的和。

然后从0到n枚举每一位改成每一位数,在这个过程中维护一个类似单调栈的东西,就是加入一个字母,将小于这个字母的值都改为负,再将正的当前字母加入。

当枚举到第i位,作为第j个字母时,i及i以后的最大的字母是max(j,i+1的后缀最大值),[i+1,n]的和通过后缀和算出,i的值通过后缀最大值讨论出正负,前面直接负的值直接加上,前面目前仍是正的值通过与i及i以后的最大的字母的关系得到正负,最后把这些加到一起得到答案取max

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int z[10];
int q[200015];
int a[200015];
int c[200015];
int ho[200015];
int b[10];
map<char,int>p;
string s;
int now=0;
int cal(int l,int r){
	if(l>r)return 0;
	return q[r]-q[l-1];
}
void add(int k){
	for(int i=1;i<k;i++){
		now-=b[i]*z[i];
		z[i]=0;
	}
	z[k]++;
}
void solve(){
memset(z,0,sizeof(z));
int ans=-1e18;
cin>>s;
ho[s.size()]=0;
for(int i=s.size()-1;i>=0;i--){
	ho[i]=max(ho[i+1],(int)(s[i]-'A'+1));
}
for(int i=0;i<s.size();i++){
	a[i]=p[s[i]];
	if(s[i]-'A'+1>=ho[i+1]){
		c[i]=1;
	}
	else	{
	c[i]=-1;
	}
}
q[0]=a[0]*c[0];
for(int i=1;i<s.size();i++){
	q[i]=q[i-1]+a[i]*c[i];
}
ans=q[s.size()-1];
now=0;
for(int i=0;i<s.size();i++){
	for(int j=1;j<=5;j++){
		int temp=cal(i+1,s.size()-1)+now;
		int li=max(j,ho[i+1]);
		for(int k=1;k<li;k++){
			temp-=z[k]*b[k];
		}
		for(int k=li;k<=5;k++){
			temp+=z[k]*b[k];
		}
		if(j>=ho[i+1])temp+=b[j];
		else temp-=b[j];
		ans=max(ans,temp);
	}
	add(s[i]-'A'+1);
}
printf("%lld\n",ans);
}
signed main(){
	p['A']=1;
	p['B']=10;
	p['C']=100;
	p['D']=1000;
	p['E']=10000;
	b[1]=1;
	b[2]=10;
	b[3]=100;
	b[4]=1000;
	b[5]=10000;
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}

D.Pairs of Segments

DP

先将线段按照r递增排序,预处理f[i],表示r<i.l 的最大下标

DP[i]表示前i个里最多选了多少个线段
D P [ i ] = m a x ( D P [ i − 1 ] , D P [ m i n ( f [ i ] , f [ j ] ) ] + 2 ) ( 线段 i 和线段 j 有交集 ) DP[i]=max(DP[i-1],DP[min(f[i],f[j])]+2)(线段i和线段j有交集) DP[i]=max(DP[i1],DP[min(f[i],f[j])]+2)(线段i和线段j有交集)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
struct node{
	int l,r;
};
bool cmp(node A,node B){
	return A.r<B.r;
}
int dp[2005];
int f[2005];
int n;
node a[2005];
void solve(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
	scanf("%lld %lld",&a[i].l,&a[i].r);
	dp[i]=0;
	f[i]=0;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
	for(int j=i+1;j<=n;j++){
		if(a[i].r<a[j].l){
			f[j]=i;
		}
	}
}
for(int i=1;i<=n;i++){
	dp[i]=dp[i-1];
	for(int j=1;j<i;j++){
		if(a[j].r>=a[i].l){
			dp[i]=max(dp[i],dp[min(f[i],f[j])]+2);
		}
	}
}
printf("%lld\n",n-dp[n]);

}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}

E.Fill the Matrix

我好像使用了特别麻烦的做法。

线段树

要找到所有相连的最长线段,然后从长到短选择

首先取
a [ i ] = n − a [ i ] a[i]=n-a[i] a[i]=na[i]
然后从1开始枚举,找到从当前点开始最远的区间没有0的区间,再找到这个区间的最小值,再把这个区间减掉这个区间最小值,同时长度为这个区间的线段个数加上这个最小值,重复这个过程直到这个点为0,所有操作均可用线段树O(logn)实现,最多修改n次(每次都会使至少一个变为0),即最多n次这个过程

最后再从大到小枚举线段长度统计答案

总复杂度:O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n,m;
int a[200005];
int ans;
int tr1[800005];//最小值
int la[800005];
int f[200005];
void  build(int k,int l,int r){
	la[k]=0;
	if(l==r){
		tr1[k]=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(k*2,l,mid);
	build(k*2+1,mid+1,r);
	tr1[k]=min(tr1[k*2],tr1[k*2+1]);
} 
void update(int k){
		tr1[k]=min(tr1[k*2],tr1[k*2+1]);
}
void pushdown(int k,int l,int r){
	tr1[k*2]+=la[k];
	la[k*2]+=la[k];
	tr1[k*2+1]+=la[k];
	la[k*2+1]+=la[k];
	la[k]=0;
}
void xi(int k,int l,int r,int l1,int r1,int w){
	if(l>=l1&&r<=r1){
		tr1[k]+=w;
		la[k]+=w;
		return;
	}
	pushdown(k,l,r);
	int mid=(l+r)/2;
	if(l1<=mid)xi(k*2,l,mid,l1,r1,w);
	if(r1>mid)xi(k*2+1,mid+1,r,l1,r1,w);
	update(k);
}
int fin(int k,int l,int r,int to){
	if(l==r){
		return tr1[k];
	}
	pushdown(k,l,r);
	int mid=(l+r)/2;
	int temp;
	if(to<=mid)temp=fin(k*2,l,mid,to);
	else temp=fin(k*2+1,mid+1,r,to);
	update(k);
	return temp;
}
int fin1(int k,int l,int r,int ls){//找>=ls第一个等于0的下标 ,没找到返回0 
	if(tr1[k]>0)return 0;
	if(l>=ls){
		if(l==r)return l;
		pushdown(k,l,r);
		int mid=(l+r)/2;
		if(tr1[k*2]==0)return fin1(k*2,l,mid,ls);
		return fin1(k*2+1,mid+1,r,ls);
	} 
	pushdown(k,l,r);
	int mid=(l+r)/2;
	int temp=0;
	if(mid>=ls)temp=fin1(k*2,l,mid,ls);
	if(!temp)temp=fin1(k*2+1,mid+1,r,ls);
	update(k);
	return temp;
}
int fin2(int k,int l,int r,int l1,int r1){
	if(l>=l1&&r<=r1){
		return tr1[k];
	}
	pushdown(k,l,r);
	int mid=(l+r)/2;
	int temp=1e9;
	if(l1<=mid)temp=min(temp,fin2(k*2,l,mid,l1,r1));
	if(r1>mid)temp=min(temp,fin2(k*2+1,mid+1,r,l1,r1));
	update(k);
	return temp;
}
int num=0;
void solve(){
	num++;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
	scanf("%lld",&a[i]);
	a[i]=n-a[i];
	f[i]=0;
}
scanf("%lld",&m);
build(1,1,n);
ans=0;
for(int i=1;i<=n;i++){
	int now=fin(1,1,n,i);
	if(!now)continue;
	while(now){
	int te=fin1(1,1,n,i);
	if(te==0)te=n;
	else te--;
	int sq=fin2(1,1,n,i,te);
	f[te-i+1]+=sq;
	xi(1,1,n,i,te,-sq);
	now-=sq;
	}
} 
for(int i=n;i>0;i--){
	if(f[i]*i<=m){
		ans+=f[i]*(i-1);
		m-=f[i]*i;
	}
	else{
		int st=m/i;
		ans+=st*(i-1);
		m-=st*i;
		if(m>1)ans+=m-1;
		m=0;
	}
}
printf("%lld\n",ans);
}
signed main(){
T=1;
//ios::sync_with_stdio(0);
//cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
solve();
}
return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值