Codeforces Round #807 (Div. 2)

Codeforces Round #807 (Div. 2)

A. Mark the Photographer

2*n 个人,问能否排成两行,使得两行对应位置的后面的人比前面的人高

排序后,前n个人作第一排,后n个人作第二排,判断一下即可

B. Mark the Dust Sweeper

给一个长度为n的序列,每次操作可以选择两个位置 i , j i,j i,j,要求满足 a i , a i + 1 , . . . , a j − 1 a_i,a_{i+1},...,a_{j-1} ai,ai+1,...,aj1均不为0

这次操作会把 a i − 1 a_i-1 ai1 a j + 1 a_j+1 aj+1,问最少多少次操作可以使得前n-1位全变成0

结论题,除去前导0,答案为所有数字之和+0的个数

C. Mark and His Unfinished Essay

给定一个长为n的字符串,然后操作c次,每次选择l-r的部分接在后面,q次询问,每次问最终得到的字符串的第x位是什么字符

发现c比较小,我们可以直接 O ( q c 2 ) O(qc^2) O(qc2)暴力向前跳,每次找到是属于哪次操作延展出来的即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
char s[maxn];
ll l[42],r[42],sum[42];
int n,c,q;
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&c,&q);
		scanf("%s",s+1);
		sum[0]=n;
		for(int i=1;i<=c;i++)
		{
			scanf("%lld%lld",&l[i],&r[i]);
			sum[i]=sum[i-1]+r[i]-l[i]+1;
		}
		//for(int i=1;i<=c;i++) printf("%lld ",sum[i]);
		//printf("\n");
		while(q--)
		{
			ll x; scanf("%lld",&x);
			int pos=c;
			for(int i=1;i<=c;i++)
				if(sum[i]>=x) {pos=i; break;}
			while(x>n)
			{
				ll delta=x-sum[pos-1]-1;
				x=l[pos]+delta;
				for(int i=1;i<=c;i++)
					if(sum[i]>=x){pos=i; break;}
			}
			//printf("%lld\n",x);
			printf("%c\n",s[x]);
		}
	}
	return 0;
}

D. Mark and Lightbulbs

给定两个01序列s和t,询问最少对s进行多少次操作可以变成t,不能输出-1

一次操作可以选择一个位置 i i i,满足 a [ i − 1 ] ! = a [ i + 1 ] a[i-1]!=a[i+1] a[i1]!=a[i+1],然后给 a [ i ] a[i] a[i]取反

发现一次操作相当于延展/收缩一段连续的0/1

那么答案就是s和t所有连续0/1段的有端点的坐标差的绝对值之和

如果s和t的连续段不对应就是无解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n;
char s[maxn],t[maxn];
int rps[maxn],rpt[maxn];
int vals[maxn],valt[maxn];
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        scanf("%s",s+1); scanf("%s",t+1);
        int cnts=0,cntt=0;
        ll ans=0;
        s[n+1]='2';
        for(int i=1;i<=n;i++)
        {
            if(s[i+1]==s[i]) continue;
            vals[++cnts]=s[i]-'0';
            rps[cnts]=i;
        }
        t[n+1]='2';
        for(int i=1;i<=n;i++)
        {
            if(t[i+1]==t[i]) continue;
            valt[++cntt]=t[i]-'0';
            rpt[cntt]=i;
        }
        /*for(int i=1;i<=cnts;i++) printf("%d ",rps[i]);
        printf("\n");
        for(int i=1;i<=cntt;i++) printf("%d ",rpt[i]);
        printf("\n");*/
        int flag=0;
        for(int i=1;i<=min(cnts,cntt);i++)
        {
            if(vals[i]!=valt[i])
            {
                flag=1;
                break;
            }
            ans+=abs(rps[i]-rpt[i]);
        }
        if(flag || cnts!=cntt) printf("-1\n");
        else 
            printf("%lld\n",ans);
    }
    return 0;
}

E. Mark and Professor Koro

给定n个数,每次可以删去两个相同的x,加入一个x+1,q次询问,每次修改一个值,问能通过操作得到的最大的值是多少

我们先把初始序列能进位的都进上去,然后得到了一个01序列,然后修改的时候就是模拟二进制加法

考虑给一个位置+1,相当于给当前位置开始的连续一段1变成0,下一个0变成1

同理,给一个位置-1,相当于给当前位置开始的连续一段0变成1,下一个1变成0

线段树模拟上述操作,区间修改,单点修改,线段树上二分到第一个0/1的位置

注意要多开log个位置,考试时少了一个pushdown WA了一发

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+65;
int n,q,m=2e5+50;
int a[maxn],b[maxn];
struct seg
{
	int val,tag;
}tr[maxn<<2];
#define lson now<<1
#define rson now<<1|1
void pushup(int now)
{
	tr[now].val=tr[lson].val+tr[rson].val;
}
void build(int now,int l,int r)
{
	if(l==r)
	{
		tr[now].val=b[l];
		return;
	}
	int mid=l+r>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(now);
}
void pushdown(int now,int l,int r)
{
	if(!tr[now].tag) return;
	int mid=l+r>>1,tag=tr[now].tag;
	tr[lson].val+=(mid-l+1)*tag;
	tr[rson].val+=(r-mid)*tag;
	tr[lson].tag+=tag; tr[rson].tag+=tag;
	tr[now].tag=0;
}
int find_0(int now,int l,int r,int L)
{
	if(tr[now].val==r-l+1) return 0;
	if(l==r) return l;
	pushdown(now,l,r);
	int mid=l+r>>1;
	if(L>mid) return find_0(rson,mid+1,r,L);
	int pos=find_0(lson,l,mid,L);
	if(!pos) pos=find_0(rson,mid+1,r,L);
	return pos;
}
int find_1(int now,int l,int r,int L)
{
	if(!tr[now].val) return 0;
	if(l==r) return l;
	pushdown(now,l,r);
	int mid=l+r>>1;
	if(L>mid) return find_1(rson,mid+1,r,L);
	int pos=find_1(lson,l,mid,L);
	if(!pos) pos=find_1(rson,mid+1,r,L);
	return pos;
}
void modify(int now,int l,int r,int L,int R,int val)
{
	if(l>=L && r<=R)
	{
		tr[now].val+=val*(r-l+1);
		tr[now].tag+=val;
		return;
	}
	int mid=l+r>>1;
	pushdown(now,l,r);
	if(L<=mid) modify(lson,l,mid,L,R,val);
	if(mid<R) modify(rson,mid+1,r,L,R,val);
	pushup(now);
}
void add(int v)
{
	int pos=find_0(1,1,m,v);
	modify(1,1,m,pos,pos,1);
	if(v!=pos) modify(1,1,m,v,pos-1,-1);  
}
void del(int v)
{
	int pos=find_1(1,1,m,v);
	modify(1,1,m,pos,pos,-1);
	if(v!=pos) modify(1,1,m,v,pos-1,1);
}
int find_pos(int now,int l,int r) 
{
	if(l==r) return l;
	int mid=l+r>>1;
	pushdown(now,l,r);
	if(tr[rson].val) return find_pos(rson,mid+1,r);
	return find_pos(lson,l,mid);
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[a[i]]++;
	for(int i=1;i<=m;i++)
	{
		b[i+1]+=b[i]/2;
		b[i]=b[i]&1;
	}
	build(1,1,m);
	int x,y;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		del(a[x]);
		add(y);
		a[x]=y;
		printf("%d\n",find_pos(1,1,m));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值