1. 程式人生 > >Codeforces Round 541 (Div. 2)

Codeforces Round 541 (Div. 2)

個數 second str 每次 表示 itl tar ORC topo


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個數 給出他們之間兩兩的比較,讓你構造出一組數據滿足這個比較

思路

首先考慮‘=‘如果有=的話說明他們的值是一樣的 所以可以把他們縮成一個點,可以減少計算量

然後對於‘>‘和"<"其實我們都可以轉化成‘>‘ 對於一個>我們可以變成一個圖,表示>右邊的那個數比左邊的小,連小一條線,說明左邊的要等右邊的數字都分配完再分配

#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;
}

Codeforces Round 541 (Div. 2)