Codeforces Round #546 (Div. 2)

A. Nastya Is Reading a Book

题意:给你若干个从小到大的区间,让你判断x所在区间离最后一个区间差多少。

签到题

#include<bits/stdc++.h>
using namespace std;
int l[105],r[105];
int main()
{
    int n,k,ans;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>l[i]>>r[i];
    cin>>k;
    for(int i=1;i<=n;i++)
        if(k>=l[i]&&k<=r[i])
        ans=n-i+1;
    cout<<ans;
}

B. Nastya Is Playing Computer Games

题意:有一个长为n的的地方,你的位置在k,每个地方都有一块石头,石头底下有一块钱,每次移动一格,拿钱,搬开石头放到旁边的格子里各花费1的时间,求捡到n块钱的最小时间花费。

签到题。

#include<bits/stdc++.h>
using namespace std;
int l[105],r[105];
int main()
{
    int n,k,ans;
    cin>>n>>k;
    if(k==1||k==n)ans=3*n;
    else
    {
        int t1=k,t2=n-k+1;
        if(t1<t2)
            ans=t1*3+t1-1+t2*3-3;
        else
            ans=t2*3+t2-1+t1*3-3;
    }
    cout<<ans;
}

C. Nastya Is Transposing Matrices

题意:你可以选取矩阵A的任意多子矩阵,让其元素按照正对角线交换,问是否能将A变成矩阵B。

思路:不难发现,我们把A矩阵每一斜行和B矩阵的每一斜行的元素排序,得到的数组如果不相同就No,如果全部相同就YES。

#include<bits/stdc++.h>
using namespace std;
int a[505][505],b[505][505],c[505],d[505],n,m;
int ok(int x,int y)
{
    int N=min(x,(n-y+1));
    for(int i=0;i<N;i++)
    {
        c[i]=a[x-i][y+i];
        d[i]=b[x-i][y+i];
    }
    sort(c,c+N);
    sort(d,d+N);
    for(int i=0;i<N;i++)
        if(c[i]!=d[i])
        return 0;
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&b[i][j]);
    n=max(n,m);
    for(int i=1;i<=n;i++)
        if(!ok(i,1)||!ok(n,i))
        puts("NO"),exit(0);
    puts("YES");
}

D. Nastya Is Buying Lunch

题意:给出n个人的位置,你在最后一个位置,给出m对可以交换的人 a b(a必须刚好在b前面才能交换),问你最多能移到前面多少。

思路:按照位置从后往前枚举每个愿意和你换位置的人,看他能否移到你这里来即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
set<int>s[maxn];
int vis[maxn],a[maxn];
int main()
{
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        s[u].insert(v);
        if(a[n]==v)vis[u]=1;
    }
    for(int i=n-1;i;i--)
    if(vis[a[i]])
    {
        for(int j=i+1;j<n;j++)
        if(s[a[j-1]].find(a[j])!=s[a[j-1]].end())
            swap(a[j-1],a[j]);
        else
            break;
    }
    for(int i=n-1;i;i--)
    if(!vis[a[i]])
    {
        printf("%d\n",n-i-1);
        return 0;
    }
    printf("%d\n",n-1);
}

E. Nastya Hasn't Written a Legend

题意:给你长度为n和长度为n-1的数组,要求ai+ki<=ai+1,有m次操作,分别为查询a数组的区间和,和让ai的值+x。如果更新后ai+1<ai+x,那么ai+1=ai+x,ai+2以及更后面同理。

思路:我们发现如果ai=ai+x后,可能会发生连锁反应,这就不好处理了,但是我们把原来的式子变形,a1<=a2-k1<=a3-k1-k2<=a4-k1-k2-k3<.....对,我们就用线段维护这个序列的区间和及区间最小值,先预处理 bi 为k1+(k1+k2)+(k1+k2+k3)+...+(...+ki-1),那么每次查询得到的值sum+br-bl-1就是答案,每次更新  i x,我先查询x点的值为res,然后从线段树中找到最大的权值不超过res+x的点 r,然后设置区间[ i ,r]的值为res+x即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll sum[maxn*4],mn[maxn*4],tag[maxn*4],a[maxn],b[maxn],inf=1e18;
void build(int o,int l,int r)
{
	tag[o]=inf;
	if(l==r)
	{
		sum[o]=mn[o]=a[l]-b[l];
		return;
	}
	int m=(l+r)/2,ls=o*2,rs=o*2+1;
	build(ls,l,m);
	build(rs,m+1,r);
	sum[o]=sum[ls]+sum[rs];
	mn[o]=min(mn[ls],mn[rs]);
}
void pushdown(int o,int ls,int rs,int l,int m,int r)
{
	if(tag[o]!=inf)
	{
		tag[ls]=tag[rs]=mn[ls]=mn[rs]=tag[o];
		sum[ls]=1ll*(m-l+1)*tag[o];
		sum[rs]=1ll*(r-m)*tag[o];
		tag[o]=inf;
	}
}
ll qu(int o,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)
	return sum[o];
	int m=(l+r)/2,ls=o*2,rs=o*2+1;	
	pushdown(o,ls,rs,l,m,r);
	ll res=0;
	if(ql<=m)res+=qu(ls,l,m,ql,qr);
	if(qr>m)res+=qu(rs,m+1,r,ql,qr);
	return res;
}
void up(int o,int l,int r,int ql,int qr,ll v)
{
	if(l>=ql&&r<=qr)
	{
		tag[o]=mn[o]=v;
		sum[o]=1ll*v*(r-l+1);
		return;
	}
	int m=(l+r)/2,ls=o*2,rs=o*2+1;
	pushdown(o,ls,rs,l,m,r);
	if(ql<=m)up(ls,l,m,ql,qr,v);
	if(qr>m)up(rs,m+1,r,ql,qr,v);
	sum[o]=sum[ls]+sum[rs];
	mn[o]=min(mn[ls],mn[rs]);
}
int qu2(int o,int l,int r,ll x)
{
	if(l==r)
	return l;
	int m=(l+r)/2,ls=o*2,rs=o*2+1;
	pushdown(o,ls,rs,l,m,r);
	if(mn[rs]<=x)return qu2(rs,m+1,r,x);
	return qu2(ls,l,m,x);	
}
int main()
{
	int n,l,r,q;
	char s[2];
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%lld",&a[i]);
	for(int i=2;i<=n;i++)
	scanf("%lld",&b[i]),b[i]+=b[i-1];
	build(1,1,n);
	for(int i=2;i<=n;i++)
	b[i]+=b[i-1];
	scanf("%d",&q);
	while(q--)
	{
		scanf("%s%d%d",s,&l,&r);
		if(s[0]=='s') 
		printf("%lld\n",qu(1,1,n,l,r)+b[r]-b[l-1]);
		else
		{
			ll x=qu(1,1,n,l,l)+r;
			int cur=qu2(1,1,n,x);
			up(1,1,n,l,cur,x);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值