Codeforces Round #771 (Div. 2)(ABCDE)

本文介绍了Codeforces Round #771 (Div.2)中五个不同题目的解题思路,包括A题的翻转操作、B题的奇偶数交换排序、C题的逆序对连通块、D题的矩阵染色和E题的彩色操作。作者分享了关键代码片段,并反思了自己的学习进展,尤其是对B、C、E题的解决方法存在不足。
摘要由CSDN通过智能技术生成

Codeforces Round #771 (Div. 2)(ABCDE)

A. Reverse
在这里插入图片描述
题意:给一个长度为n的排序,可以翻转一次,使得字典序最小
思路:从前到后遍历,位置 i ! = a [ i ] i!=a[i] i!=a[i],则翻转区间左端点i,右端点为值i所在位置

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,a[N];

void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int l=-1,r=-1;
    for(int i=1;i<=n;i++){
        if(a[i]==i) continue;
        else {l=i;break;}
    }
    if(l==-1){
        for(int i=1;i<=n;i++) printf("%d ",i);
        puts("");
        return;
    }
    if(l!=-1){
        for(int i=l+1;i<=n;i++){
            if(a[i]==l){r=i;break;}
        }
    }
    for(int i=1;i<l;i++) printf("%d ",a[i]);
    for(int i=r;i>=l;i--) printf("%d ",a[i]);
    for(int i=r+1;i<=n;i++) printf("%d ",a[i]);
    puts("");
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

B. Odd Swap Sort
在这里插入图片描述题意:当两个 ( a [ i ] + a [ i + 1 ] ) (a[i]+a[i+1])%2==1 (a[i]+a[i+1])时,可以交换两个值的位置,问最后是否可以使得序列为不降序列
思路:发现只能奇数和偶数交换,那么将奇数和偶数分开,初始奇数和偶数都为不降序列就yes,否则no

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,a[N];

void solve(){
    vector<int>odd,even,odd1,even1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]%2==1) odd.push_back(a[i]);
        else even.push_back(a[i]);
    }
    odd1=odd;even1=even;
    sort(odd.begin(),odd.end());
    sort(even.begin(),even.end());
    for(int i=0;i<odd.size();i++){
        if(odd[i]==odd1[i]) continue;
        else {puts("NO");return;}
    }
    for(int i=0;i<even.size();i++){
        if(even[i]==even1[i]) continue;
        else {puts("NO");return;}
    }
    puts("YES");
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

C. Inversion Graph
在这里插入图片描述
题意:给长度为n的一种排列,每个逆序对可以连一根线,问最后有多少连通块
思路:从后往前,如果当前位置 i = = a [ i ] i==a[i] i==a[i],那么就单独构成一个连通块,否则说明在左边(前面)区间 [ 1 , i − 1 ] [1,i-1] [1,i1]有一个位置 l l l的数值为i。对于中间区间 [ l , i ] [l,i] [l,i]。分类讨论,如果比 l l l小,则更新 l l l,如果比 l l l大,则说明可以直接构成逆序对合成一个连通块,最后得到答案。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,a[N];

void solve(){
    int sum=0;
    map<int,int>mp;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]=i;
    for(int i=n;i>=1;){
        sum++;
        if(a[i]==i) i--;
        else{
            int l=a[i],pos=i;
            while(pos>=l){
                if(pos==l){
                    if(a[pos]>l) {i=pos-1;break;}
                    else l=a[pos];
                }
                else{
                    if(a[pos]>=l) pos--;
                    else l=a[pos];
                }
            }
        }
    }
    printf("%d\n",sum);
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

D. Big Brush
在这里插入图片描述题意:将一个nm的矩阵用22的矩阵染色,是否可以染色想要颜色,可以输出次数和染色方案,不可以输出-1
思路:倒过来想,每次去看哪些点可以染色,如果已经染成目标颜色,就将颜色清空变成"万能色",如果对未到达目标颜色的点 ( i , j ) (i,j) (i,j)进行染色,当且仅当其负责的2*2矩阵中有”万能色“,或有颜色与之相同。最后还剩下颜色点就表示无法完成染色输出-1

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,a[N][N];
bool vis[N][N];
int dx[]={-1,-1,-1,0,0,1,1,1};
int dy[]={-1,0,1,-1,1,-1,0,1};
struct node{int x,y,col;};
vector<node>ans;

int merge(int &x,int y){
    if(x==y)return 1;
    if(x==0||y==0) {x=x+y;return 1;}
    return 0;
}

void cek(int x,int y){
    if(x<1||x>=n||y<1||y>=m) return;
    if(vis[x][y]) return;
    int color=a[x][y];
    if(!merge(color,a[x+1][y])) return;
    if(!merge(color,a[x][y+1])) return;
    if(!merge(color,a[x+1][y+1])) return;
    vis[x][y]=true;
    if(color) ans.push_back({x,y,color});
    a[x][y]=a[x+1][y]=a[x][y+1]=a[x+1][y+1]=0;
    for(int i=0;i<8;i++) cek(x+dx[i],y+dy[i]);
}

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++){
            cek(i,j);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]){
                puts("-1");
                return 0;
            }
        }
    }
    int len=ans.size();
    printf("%d\n",len);
    for(int i=len-1;i>=0;i--) printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].col);
    return 0;
}

E. Colorful Operations
在这里插入图片描述题意:
长度为n的序列,初始每个位置val=0,color=1
Color l,r,c: 区间[l,r]的颜色改成c
Add c x:所有颜色为c的位置val+=x
Query i:输出i位置的val
思路:
set记录每个区间的左端点,r[i]代表i所在区间的右端点,col[i]为i当前颜色,val[i]为颜色i的价值
tr[i]=val[i]-val[j] 每次改变颜色都先减去当前要变为颜色的当前值,最后算的时候加上当前颜色值就行了
同时用树状数组来记录单点的值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+5;
ll n,q,val[N],color[N],R[N],tr[N];
set<ll>L;

ll lowbit(ll x){return x&(-x);}

void insert(ll x,ll v){
    while(x<N){
        tr[x]+=v;
        x+=lowbit(x);
    }
}

void seg(ll l,ll r,ll v){
    insert(l,v);
    insert(r+1,-v);
}

void Color(ll l,ll r,ll c){
    while(1){
        auto it=L.lower_bound(l);
        if(*it>r) break; //当前下一个区间与修改区间无交集
        if(R[*it]>r){//当前下一个区间左端点在修改区间内,右端点在修改区间外
            seg(*it,r,val[color[*it]]);
            R[r+1]=R[*it];
            color[r+1]=color[*it];
            L.erase(*it);
            L.insert(r+1);
        }
        else{//修改区间包含当前区间
            seg(*it,R[*it],val[color[*it]]);
            L.erase(*it);
        }
    }
    L.insert(l);
    R[l]=r;
    color[l]=c;
    seg(l,r,-val[c]);

    auto it=prev(L.lower_bound(l));
    if(R[*it]>=l){
        if(R[*it]>r){//当前区间包含修改区间
            seg(l,r,val[color[*it]]);
            R[r+1]=R[*it];
            R[*it]=l-1;
            color[r+1]=color[*it];
            L.insert(r+1);
        }
        else{当前下一个区间左端点在修改区间外,右端点在修改区间内
            seg(l,R[*it],val[color[*it]]);
            R[*it]=l-1;
        }
    }
}

void Add(ll c,ll x){val[c]+=x;}

ll cal(ll x){
    ll ans=0;
    while(x){
        ans+=tr[x];
        x-=lowbit(x);
    }
    return ans;
}

ll Query(ll pos){return val[color[*prev(L.upper_bound(pos))]]+cal(pos);}

int main(){
    scanf("%lld%lld",&n,&q);
    L.insert(0); R[0]=0;
    L.insert(n+1); R[n+1]=n+1;
    L.insert(1); R[1]=n,color[1]=1;
    for(ll i=1;i<=q;i++){
        char op[6];
        scanf("%s",op);
        if(op[0]=='C'){
            ll l,r,c;scanf("%lld%lld%lld",&l,&r,&c);
            Color(l,r,c);
        }
        else if(op[0]=='A'){
            ll c,x;scanf("%lld%lld",&c,&x);
            Add(c,x);
        }
        else {
            ll pos; scanf("%lld",&pos);
            printf("%lld\n",Query(pos));
        }
    }
    return 0;
}

总结
B题开始用数组导致wa2,之后用vector水过
CD题写的有点慢
E题不会写
结论:只会A题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值