Codeforces Round #819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022 A-D

A. Mainak and Array

a有三种情况
一种是整个环都在转
另外两种是一个端点不转,其它点都在转
取个最值就可了

//#define int ll
const int N = 2e5+10;
int n,m;
 
int a[N];
 
void solve()
{
//    cin>>n>>m;
    cin>>n;
    int mx = 0;
    fo(i,1,n) cin>>a[i];
    fo(i,1,n-1) {
        mx = max(mx,a[i] - a[i+1]);
    }
    mx = max(a[n] - a[1],mx); 
    int t1 = a[1],t2 = a[n];
    
    sort(a+1,a+1+n);
    cout<<max({t2 - a[1],a[n] - t1,mx})<<endl;  
}

B. Mainak and Interesting Sequence

分奇偶
而且如果m < n一定是no
m是奇数 n 是偶数也一定是no
两个都是偶数也是特殊情况

//#define int ll
const int N = 1e5+10;
int n,m; //13 / 2
//13 / 4//不行 //12 / 5//可以 //12 / 8//可以 
//13 / 3//可以 
 
void solve()
{
    cin>>n>>m;
    if(m < n) {
        cout<<"No"<<endl;rt;
    }
    
    if(m % n == 0) {
        cout<<"Yes"<<endl;
        fo(i,1,n) {
            cout<<m / n<<' ';
        } cout<<endl;
    } else {
        if(m % 2 == 1 && n % 2 == 0) {
            cout<<"No"<<endl;rt;
        } else {
            cout<<"Yes"<<endl;
            if(m % 2 == 1) {
                int t = m / n;
                fo(i,1,n-1) {
                    cout<<t<<' ';
                } cout<<m - t * (n -1)<<endl;
            } else {
                
                if(n % 2 == 1) {
                    int t = m / n;
                    fo(i,1,n-1) {
                        cout<<t<<' ';
                    } cout<<m - t * (n -1)<<endl;
                } else {
                        int t = m / n;
                    fo(i,1,n-2) {
                        cout<<t<<' ';
                    } cout<<(m - t * (n - 2)) / 2<< ' '<<(m - t * (n - 2)) / 2 <<endl;
                }
            }
        }
    }
}

 

C. Jatayu's Balanced Bracket Sequence

AB是合法序列,(A)也是合法序列,但是(A)不能减少连通块的个数,AB,则A最左边的 (  和B最右边的 ) 可以构成合法序列,连通块-1

一开始有n 个连通块,假如碰到 )( 连通块个数 -1

//#define int ll
const int N = 1e5+10;
int n,m;
 
void solve()
{
//    cin>>n>>m;
    cin>>n;
    int ans = n;
    string s;cin>>s;
    fo(i,1,2*n-1) {
        if(s[i] == '(' && s[i-1] == ')') {
            --ans;
        }
    }    
    cout<<ans<<endl;
}

D. Edge Split

最多n+2个边,也就是有三个环

假如没有环,将所有边染成红色和将一半的边染成红色结果是一样的

当一个图里增加一个环,连通块个数是不会变的,就会浪费一条边

考虑有环

将图拆了,生成一颗树。

剩下的边都是0

假如剩下三个点,也就是说它们两两有环

最方便的做法是保存这三个点的深度,以及这个点之前的点连到这个点的边

然后将一号点到三号点的边染成红色,并将三号点到之前的边染成蓝色,就不会出现环

const int N = 2e6+10,M = 2 * N;
bool vis[N];
int n,m,ans[N];
int h[N],ne[M],w[M],e[M],idx; 
int pre[N],depth[N];

struct node {
    int a,b,id;
};
V<node> extra;
set<int>s; 

void add(int a,int b,int c) {
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ,w[idx - 1] = c;
}

void dfs(int u) {
    vis[u] = 1;
    for(int i = h[u];~i;i=ne[i]) {
        int j = e[i];
        if(!vis[j]) {
            pre[j] = w[i];
            depth[j] = depth[u] + 1;
            dfs(j);
            ans[w[i]] = 1;
        } else if(depth[j] > depth[u]) {
            extra.pb({u,j,w[i]});
            s.insert(j);
            s.insert(u);
        }
    }
}

void solve()
{
    cin>>n>>m;
    s.clear();
    extra.clear();
    fo(i,0,n) {
        vis[i] = pre[i] = depth[i] = 0;
        h[i] = -1;
    }
    fo(i,0,m) ans[i] = 0;
    fo(i,1,m) {
        int u,v;cin>>u>>v;
        add(u,v,i);
        add(v,u,i);
    }
    dfs(1);
    if(extra.size() == 3 && s.size() == 3) {
        vector<int> a(s.begin(),s.end());
        sort(a.begin(),a.end(),[&](int i,int j) {
            return depth[i] < depth[j];
        });
        for(auto it:extra) {
            int u = it.a,v = it.b,id = it.id;
            if(u == a[0] && v == a[2]) ans[id] = 1;
        }
        ans[pre[a[2]]] = 0;
    }
    fo(i,1,m) cout<<ans[i];
    cout<<endl;
}

 

posted @ 2022-09-07 23:58  er007  阅读(107)  评论(0编辑  收藏  举报