Codeforces Round #546 (Div. 2) 题解

Codeforces Round #546 (Div. 2)

题目链接:https://codeforces.com/contest/1136

A. Nastya Is Reading a Book

题意:

一本书有n个章节,之后给出每个章节所在页数范围,然后有一个人来看书看了k页,问还有多少章节没看。

 

题解:

水题。模拟一下就好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n;
int l[N],r[N];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>l[i]>>r[i];
    int k;
    cin>>k;
    int p = lower_bound(l+1,l+n+1,k)-l;
    if(l[p]==k) cout<<n-p+1;
    else cout<<n-p+2;
    return 0;
}
View Code

 

B. Nastya Is Playing Computer Games

题意:

有n个格子,每个格子一开始都有一个硬币,硬币上面都有一个石头。现在有一个人在k这个位置,问他需要多少次操作能将所有的硬币捡完。操作可以分为以下三类:

1.左右移动一格;2.将当前硬币上面的石头扔向另外一个格子(可以自己选择);3.捡起当前的硬币。

 

题解:

思路就是将操作分开看,移动所需要的花费以及捡硬币所需要的花费。这里扔石头是有贪心思想的,也就是说我们尽可能地将石头扔向那些没有硬币的格子中。

具体看代码吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n,k;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>k;
    cout<<n + n+1 + n-1+min(n-k,k-1);
    //捡硬币,扔石头,和移动 
    return 0;
}
View Code

 

C. Nastya Is Transposing Matrices

题意:

给出两个矩阵,现在你可以对第一个矩阵的任意一个子矩阵进行转置操作,即将行列对换,可以进行多次操作。最后问是否能够将第一个矩阵变为第二个矩阵。

 

题解:

观察转置操作,其实就是将一条对角线上面的数进行了重排列。那么我们就可以将一个较大矩阵的操作,变为许多2*2矩阵的转置操作(改变对角线)。

所以我们只需要判断一下两个矩阵对角线上面的值是否一样就行了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 505;
int n,m;
int a[N][N];
int b[N][N];
vector <int> vec1,vec2;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>b[i][j];
    int last=0;
    for(int k=2;k<=n+m;k++){
        vec1.clear();vec2.clear();
        int i,j;
        if(k<=1+m) i=1;
        else i=k-m;
        j = k-i;
        //cout<<endl<<endl;
        while(i<k && i<=n && j>=1){
            //cout<<i<<" "<<j<<endl;
            vec1.push_back(a[i][j]);
            vec2.push_back(b[i][j]);
            i++;j--;
        }
        sort(vec1.begin(),vec1.end());
        sort(vec2.begin(),vec2.end());
        int s=vec1.size();
        for(i=0;i<s;i++){
            if(vec1[i]!=vec2[i]){
                cout<<"NO";
                return 0;
            }
        }
    }
    cout<<"YES";
    return 0;
}
View Code

 

D. Nastya Is Buying Lunch

题意:

有n个人从左到右站立,然后有m个规则:每个规则里面描述的就是,如果有一个人在另一个人前面,那么这两个人就可以交换位置。问最后一个人最多可以到多前面去。

 

题解:

这个题我一开始乱写一发过了70个点,后面认真想了下,就WA4了。。

其实这个题可以发现一个数量关系,如果一个人目前的位置在pos处,那么如果后面有n-pos个人可以和他交换,那么他就肯定能和最后一个人交换。

当然这里的n-pos是除开某些已经和最后一个人交换了的人的。所以从后扫一下就行了,具体见代码吧。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+5;
int n,m;
int a[N],cnt[N],p[N];
vector <int> g[N];
void adde(int u){
    for(auto v:g[u]) cnt[v]++;
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],p[a[i]]=i;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[v].push_back(u);
    }
    int ans = 0;
    adde(a[n]);
    for(int i=n-1;i>=1;i--){
        if(cnt[a[i]]==n-i-ans) ans++;
        else adde(a[i]);
    }
    cout<<ans;
    return 0;
}
View Code

 

E. Nastya Hasn't Written a Legend

题意:

给出n个数,然后给出n个数的权值以及对应的ki,现在有两种操作,一个是询问区间和,另一个就是对某个位置上的数加上x,然后对于所有后面的数,如果ai+1<ai+ki,就让ai+1=ai+ki

 

题解:

这个题需要转化一下,因为题目一开始保证了ai+1>=ai+ki的,然后令ti=k1+k2+...+ki,那么两边同时减去ti,最后变为ai+1-ti>=ai-ti-1,然后我们构造bi=ai-ti-1,所以题目中的条件就转化为了bi+1>=bi

接下来再看题目中的操作,求和操作很简单,求出对应bi的和,然后减去加上的值就行了;然后就是加法操作,如果bi加上x,那么后面小于bi+x的都要变为bi+x,这里用线段树查询一下第一个大于等于bi+x的位置就行了,具体方法就是先看左子树,再看右子树。

这个构造方法可行的原因就在于,如果有ai+1<ai+x+ki,那么也必然有bi+1<bi+x,这个比较显然,同时减去一个数并不改变等号。

代码如下:

#include <bits/stdc++.h>
#define INF 999999999999999
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n;
ll a[N],b[N],t[N],k[N],pre[N];
struct Seg_Tre{
    int l,r;
    ll lazy,sum,mx;
}tre[N<<2];
void push_up(int rt){
    tre[rt].sum=tre[rt<<1].sum+tre[rt<<1|1].sum;
    tre[rt].mx=max(tre[rt<<1].mx,tre[rt<<1|1].mx);
}
void push_down(int rt){
    if(tre[rt].lazy!=INF){
        ll lzy=tre[rt].lazy;
        tre[rt<<1].sum=lzy*(tre[rt<<1].r-tre[rt<<1].l+1);
        tre[rt<<1|1].sum=lzy*(tre[rt<<1|1].r-tre[rt<<1|1].l+1);
        tre[rt<<1].mx=lzy;
        tre[rt<<1|1].mx=lzy;
        tre[rt].lazy=INF;
        tre[rt<<1].lazy=lzy;tre[rt<<1|1].lazy=lzy;
    }
}
void build(int rt,int l,int r){
    tre[rt].l=l;tre[rt].r=r;tre[rt].lazy=INF;
    if(l==r){
        tre[rt].sum=tre[rt].mx=b[l];
        return ;
    }
    int mid = l+r>>1;
    build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
    push_up(rt);
}
ll query_sum(int rt,int l,int r){
    int L=tre[rt].l,R=tre[rt].r;int mid=L+R>>1;
    if(l<=L&&R<=r){
        return tre[rt].sum;
    }
    push_down(rt);
    ll ans = 0;
    if(l<=mid) ans+=query_sum(rt<<1,l,r);
    if(r>mid) ans+=query_sum(rt<<1|1,l,r);
    push_up(rt);
    return ans ;
}
ll query_pos(int rt,ll val){
    int L=tre[rt].l,R=tre[rt].r;
    int mid=L+R>>1;
    if(L==R) return L;
    ll p;
    push_down(rt);
    if(tre[rt<<1].mx>=val) p=query_pos(rt<<1,val);
    else p=query_pos(rt<<1|1,val);
    return p;
}
void update(int rt,int l,int r,ll val){
    int L=tre[rt].l,R=tre[rt].r;
    int mid=L+R>>1;
    if(l<=L&&R<=r){
        tre[rt].lazy=val;
        tre[rt].sum=val*(R-L+1);
        tre[rt].mx=val;
        return ;
    }
    push_down(rt);
    if(l<=mid) update(rt<<1,l,r,val);
    if(r>mid) update(rt<<1|1,l,r,val);
    push_up(rt);
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<n;i++){
        cin>>k[i];
        k[i]+=k[i-1];
        pre[i]=pre[i-1]+k[i];
    }
    for(int i=1;i<=n;i++) b[i]=a[i]-k[i-1];
    build(1,1,n);
    int q,x,y;char c;
    cin>>q;
    while(q--){
        //getchar();
        cin>>c>>x>>y;
        if(c=='s'){
            ll ans = query_sum(1,x,y);
            cout<<ans+pre[y-1]-(x>=2?pre[x-2]:0)<< '\n';
        }else{
            ll st = query_sum(1,n,n);
            ll now = query_sum(1,x,x)+y;
            ll r = query_pos(1,now);
            if(r==n && st<now) r=n+1;
            update(1,x,r-1,now);
            //cout<<x<<" "<<r<<" "<<now+y<< '\n';
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/heyuhhh/p/10549156.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值