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

Posted 斗奋力努

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #771 (Div. 2)(ABCDE)相关的知识,希望对你有一定的参考价值。

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 nodeint 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以上是关于Codeforces Round #771 (Div. 2)(ABCDE)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Codeforces Round #771 (Div. 2) A~E

Codeforces Round #771 (Div. 2) A~E

Codeforces Round #771 (Div. 2) A~E

Codeforces Round #436 E. Fire(背包dp+输出路径)