Codeforces Round 541 (Div. 2)


layout: post
title: Codeforces Round 541 (Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- 并查集
---

传送门

A.Sea Battle (签到)

题意

给你一个上下两个矩形,让他们左边对着拼起来,求出他们外面一圈的面积

思路

关键就是中间那一块留面积大的就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    ll a,b,c,d;
    cin>>a>>b>>c>>d;
    ll ans=0;
    ans+=(a+2)*(b+1);


    ans+=(c+2)*(d+1);

    ans-=min(a+2,c+2);

    ans+=max(a+2,c+2);
    ans-=a*b+c*d;
    cout<<ans;
    return 0;
}

B.Draw! (模拟)

题意

按顺序给你一堆比分,问你最多能出现几场胜场

思路

也是直接模拟,不过要注意平局的时候

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    ll ans=1;
    int n;
    cin>>n;
    ll aa=0,bb=0;
    for(int i=1;i<=n;i++){
        ll a,b;
        cin>>a>>b;
        if(a<bb||b<aa){
            aa=a,bb=b;continue;
        }
        ans+=min(a,b)-max(aa,bb)+1;
        if(aa==bb)ans--;
        aa=a,bb=b;
    }
    cout<<ans;
    return 0;
}

C.Birthday (模拟)

题意

给你一堆高度,让你重新排成一个圆使得对于任意一个高度她周围的差尽可能小

思路

对于一个数,那么她周围的肯定是和他最近的数,所以直接排序一下,拿一个双端队列前后模拟一下就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int a[maxn];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    sort(a+1,a+1+n);
    deque<int>dq;
    for(int i=1;i<=n;i++){
        if(i&1)
            dq.push_back(a[i]);
        else dq.push_front(a[i]);
    }
    for(int i=1;i<=n;i++){
        cout<<dq.front()<<" ";
        dq.pop_front();
    }
    return 0;
}

D.Gourmet choice (并查集缩点+拓扑排序)

题意

有N+M个数 给出他们之间两两的比较,让你构造出一组数据满足这个比较

思路

首先考虑'='如果有=的话说明他们的值是一样的 所以可以把他们缩成一个点,可以减少计算量

然后对于‘>'和"<"其实我们都可以转化成'>' 对于一个>我们可以变成一个图,表示>右边的那个数比左边的小,连小一条线,说明左边的要等右边的数字都分配完再分配

扫描二维码关注公众号,回复: 5304697 查看本文章
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int n,m;
int fa[maxn],d[maxn],a[maxn];
vector<int>G[maxn];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
char s[2005][2005];
void add(int i,int j){
    int aa=find(i),bb=find(j);
    if(aa==bb)puts("No"),exit(0);
    d[aa]++;
    G[bb].push_back(aa);
}
int vis[maxn];
void topo(){
    queue<pair<int,int> >Q;
    for(int i=1;i<=n+m;i++){
        int aa=find(i);
        if(!d[aa]&&!vis[aa])Q.push(make_pair(aa,1)),vis[aa]=1;
    }
    while(!Q.empty()){
        pair<int,int> now=Q.front();Q.pop();
        int u=now.first;
        a[u]=max(a[u],now.second);
        for(auto i:G[u]){
            a[i]=max(a[u]+1,a[i]);
            d[i]--;
            if(!d[i])Q.push(make_pair(i,a[i]));
        }
    }
    for(int i=1;i<=n+m;i++)
        if(d[i])puts("No"),exit(0);
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n+m;i++)fa[i]=i;
    for(int i=1;i<=n;i++){
        cin>>s[i]+1;
        for(int j=1;j<=m;j++){
            if(s[i][j]=='='){
                int aa=find(i),bb=find(j+n);
                fa[bb]=aa;
            }
           /* else if(s[j]=='>'){
                add(i,j+n);
            }
            else add(n+j,i);*/
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
        if(s[i][j]=='>')add(i,n+j);
        if(s[i][j]=='<')add(n+j,i);
        }
    topo();
    cout<<"Yes"<<endl;
    for(int i=1;i<=n;i++)cout<<a[find(i)]<<" ";cout<<endl;
    for(int j=1;j<=m;j++)cout<<a[find(j+n)]<<" ";
    return 0;
}
/*
3 3
<<<
<<=
<<=
*/

E.String Multiplication(DP)

题意

定义一种字符串乘法 如果aab*c变成cacacbc

就是用后一个字符串填满前一个字符串的空隙和前后

问你n个乘法过后的结果字符串的最长连续相同字母是多少

思路

可以发现答案又最后一种字符串控制,因为就算前面的答案是多少都会被最后一个字符串拆开

所以分析最后一个字符串,发现情况有三种

如果最后一个字符串字符只有一种,那么答案就为这个前面那个字符串的这个字符长度+1 并且乘上最后一个字符串的长度 + 前面那个字符串的长度

如果是 不是的话那么答案就只和最后字符串的前后字符有关系,答案就是当前字符串的前后最长长度+(前面的答案是否有包含这个字符) 如果前后的字符都一样的话那么答案又不同了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int dp[maxn][26],a[26],head,tail,ans;
char s[maxn];
void init(){
    memset(a,0,sizeof(a));
    int n=strlen(s+1),t=1;
    for(int i=2;i<=n;i++){
        if(s[i]!=s[i-1])
            a[s[i-1]-'a']=max(a[s[i-1]-'a'],t),t=1;
        else t++;
    }
    a[s[n]-'a']=max(a[s[n]-'a'],t);
    head=tail=1;
    for(int i=2;i<=n;i++)
        if(s[i]==s[i-1])head++;
        else break;
    for(int i=n-1;i>=1;i--)
        if(s[i]==s[i+1])tail++;
    else break;
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s+1;
        int len=strlen(s+1);
        init();
        if(head==len){
            int k=s[1]-'a';
            dp[i][k]=head*(dp[i-1][k]+1)+dp[i-1][k];
        }
        for(int j=0;j<26;j++){
            dp[i][j]=max(dp[i][j],a[j]);
            if(dp[i-1][j]){
                dp[i][j]=max(dp[i][j],1);
                int p1=0,p2=0;
                if(s[1]==char('a'+j)){
                    p1=1;
                    dp[i][j]=max(dp[i][j],head+1);
                }
                if(s[len]==char('a'+j)){
                    p2=1;
                    dp[i][j]=max(dp[i][j],tail+1);
                }
                if(p1&&p2)dp[i][j]=max(dp[i][j],head+tail+1);
            }
            if(i==n)ans=max(ans,dp[i][j]);
        }
    }
    cout<<ans;
    return 0;
}

F.Asya And Kittens (启发式合并 or ripe黑科技 or 链表操作)

题意

给你n-1对,相邻的在一块,选了这两个数,这两个集合就可以看成一个集合了,问符合条件的序列。

思路

很容易想到并查集的合并操作,对于一次合并相当于把两个集合变成了一块,那么现在的问题就是怎么处理集合合并

方法有三,

1.启发式合并,每次把容量小的合并到容量大的里面去,这样可以保证复杂度是log

2.链表,这样直接把头指针插到另一个的尾指针上,每一个的操作复杂度为o(1)

3.rope 黑科技,

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int fa[maxn];
vector<int>G[maxn];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        fa[i]=i;G[i].push_back(i);
    }
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        int fx=fa[x],fy=fa[y];
        if(G[fx].size()<G[fy].size())swap(fx,fy);
        for(int j=0;j<G[fy].size();j++){
            G[fx].push_back(G[fy][j]);
            fa[G[fy][j]]=fx;
        }
        G[fy].clear();
    }
    for(int i=0;i<n;i++){
        cout<<G[fa[1]][i]<<" ";
    }
    return 0;
}

rope

#include<bits/stdc++.h>
#include<ext/rope>
using namespace __gnu_cxx;
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
rope<int>a[maxn];
int fa[maxn];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        a[i].push_back(i);
        fa[i]=i;
    }
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        x=find(x),y=find(y);
        a[x]+=a[y];
        fa[y]=x;
    }
    for(int i=1;i<=n;i++){
        if(find(i)==i){
            for(int j=0;j<a[i].size();j++)cout<<a[i][j]<<" ";
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luowentao/p/10427504.html