Codeforces Round #541 (Div. 2) 题解

Codeforces Round #541 (Div. 2)

题目链接:https://codeforces.com/contest/1131

A. Sea Battle

题意:

给出两个矩形的宽和高,满足第一个矩形的左上顶点为(0,0),右下顶点为(w1,-h1);第二个矩形的坐下顶点为(0,0),右上顶点为(w2,h2)。然后求围绕这两个矩形一圈的格子个数为多少。

题解:

利用二维前缀和的思路推导一下公式就行了,公式也有很多吧==我当时就是大概模拟了一下。。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll w1,h1,w2,h2;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>w1>>h1>>w2>>h2;
    ll ans = 0;
    ans+=(h1+h2+2)*(max(w1,w2)+2);
    ll now=min(w1,w2);
    ll tmp=max(w1,w2)-now;
    if(w1<w2) ans-=h1*tmp;
    else ans-=h2*tmp;
    ans-=(w1*h1+w2*h2);
    cout<<ans;
    return 0;
}

B. Draw!

题意:

给出n次两个人的比分,每次给出xi,yi代表两个人的比分,然后问这两个人最多平局的多少次。

题解:

假设这两个人在比分为p的时候平局,对于xi,yi,xi+1,yi+1来说,肯定满足max(xi,yi)<=p<=min(xi+1,yi+1)的,然后就借用这个式子来算。注意一下xi==yi这种特殊情况,可能会被计算多次,处理一下就好了。

原谅我代码对不上上面的题解。。懒得改了,我感觉我的做题思路还没有抽象化,上面一题也是,基本都是采用模拟的方法来做的,没有很好地进行数学建模。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10005;
int n;
int a[N],x[N],y[N];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    ll ans = 1;
    for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
    ans+=min(x[1],y[1]);
    for(int i=2;i<=n;i++){
        if(x[i]>y[i]){
            int dx=x[i]-x[i-1],dy=y[i]-y[i-1];
            if(y[i]<x[i-1]) continue ;
            if(y[i-1]<x[i-1]) ans+=(y[i]-x[i-1]+1);
            else if(y[i-1]>x[i-1]) ans+=dy+1;
            else ans+=min(dx,dy);
        }else{
            int dx=x[i]-x[i-1],dy=y[i]-y[i-1];
            if(x[i]<y[i-1]) continue ;
            if(x[i-1]<y[i-1]) ans+=(x[i]-y[i-1]+1);
            else if(x[i-1]>y[i-1]) ans+=dx+1;
            else ans+=min(dx,dy);
        }
    }
    cout<<ans;
}

C. Birthday

题意:

n个人,每个人都有对应的身高ai,然后这n个人站成一个圈,问怎样的站法,能够使相邻两个人的身高差最小,最后任意输出一种方法即可。

题解:

考虑贪心的做法(为啥这题的数据为100啊...),先对所有的数排个序,然后从前往后依次放奇数位置的人,从后往前依次放偶数位置的人。

题解的证明用到了哈密顿回路,我们这种做法得到的答案为max(ai+2-ai),然后只需要证明不可能存在max(ai+1-ai)这样的答案就行了,证明这个在直观上面还是比较好理解的,很容易得证。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int a[N],ans[N];
int n;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    int fir=1,last=n;
    for(int i=1;i<=n;i++){
        if(i&1){
            ans[fir++]=a[i];
        }else ans[last--]=a[i];
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    return 0;
}

D. Gourmet choice

题意:

给出一个n*m的符号矩阵,分别对应第n个数和第m个数的大小关系,然后让你根据这个矩阵构造这n+m个数,如果得不到就输出"No"。

题解:

其实根据大小关系很容易想到拓扑排序,小的向大的连边,然后如果无环就存在一种情况。

但是这里有等于符号,在本题中,等于的那些数本质上是相等的,也就是说拥有相同的拓扑序,那我们用并查集缩点处理即可。

然后跑拓扑排序,途中标记答案,最后根据输出就行了。

注意一下这种情况:就是如果一些点都属于一个集合中,但是有些点的关系存在不等关系,这就矛盾了,要判断一下。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1005;
int n,m,cnt,tot;
char mp[N][N];
int f[N<<1],num[N<<1],head[N<<1],in[N<<1],ans[N<<1];
struct Edge{
    int u,v,next;
}e[N*N<<1];
int find(int x){
    return f[x]==x?f[x]:f[x]=find(f[x]);
}
void Union(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx==fy) return ;
    f[fx]=fy;
}
void adde(int u,int v){
    e[tot].v=v;e[tot].next=head[u];head[u]=tot++;
}
int topsort(){
    queue <int> q;
    int tot=0;
    for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i),tot++,ans[i]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(--in[v]==0){
                ans[v]=ans[u]+1;
                q.push(v);
                tot++;
            }
        }
    }
    return tot==cnt;
}
int main(){
    scanf("%d%d",&n,&m);
    int flag=0;
    for(int i=1;i<=n+m;i++) f[i]=i;
    for(int i=1;i<=n;i++){
        scanf("%s",mp[i]+1);
        for(int j=1;j<=m;j++){
            if(mp[i][j]==‘=‘) Union(i,j+n);
            else flag=1;
        }
    }
    for(int i=1;i<=n+m;i++){
        int f=find(i);
        if(!num[f]) num[f]=++cnt;
    }
    if(cnt==1 && flag){
        cout<<"No";
        return 0;
    }
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int u=num[find(i)],v=num[find(j+n)];
            if(u==v&&mp[i][j]!=‘=‘){
                cout<<"No";
                return 0;
            }
            if(mp[i][j]==‘<‘) adde(u,v),in[v]++;
            else if(mp[i][j]==‘>‘) adde(v,u),in[u]++;
        }
    }
    int f=topsort();
    if(!f) cout<<"No";
    else{
        puts("Yes");
        for(int i=1;i<=n+m;i++){
            int fx=find(i);
            cout<<ans[num[fx]]<<" ";
            if(i==n) cout<<‘\n‘;
        }
    }
    return 0;
}

F. Asya And Kittens

题意:

有n个数乱序排列,每个数都互不相等,并且它们中间有n-1个隔板将它们分离。现在每次会抽出两个数之中的隔板,进行n-1次操作,最终n个数之中没有隔板,最后输出这n个数排列的一种情况。注意题目中给出的两个数,不一定是相邻的,但它们一定在相邻的两个块中。

题解:

对于两个相邻的块,我们直接合并就行了,往左或者右合并都行,因为反正它们都会成为一个块。这里用并查集的话就要启发式合并,减少空间的消耗,具体点就是将size小的集合往size大的集合合并,这样可以节约总空间,并且可以证明空间复杂度不超过O(nlogn);如果不这样合并,空间复杂度上界可能为O(n^2)。

当然这里有个黑科技rope,用这个来储存十分节约空间,对于这个题怎么合并都行,并且单次插入、删除等操作都是O(logn)的复杂度,常数稍微大了点,但是已经十分优秀了。这个底层是用平衡树来搞的,似乎可以来代替块状链表= =反正就是个类似于链表的东西。

代码如下:

#include <bits/stdc++.h>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
const int N = 150005;
int n;
int f[N];
rope <int> a[N];
int find(int x){
    return f[x]==x ? f[x] : f[x]=find(f[x]);
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) f[i]=i,a[i]=i;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        int fx=find(x),fy=find(y);
        if(fx==fy) continue ;
        f[fx]=fy;
        a[fy]+=a[fx];
    }
    for(int i=1;i<=n;i++){
        int f=find(i);
        if(f==i){
            for(int j=0;j<a[f].size();j++){
                cout<<a[f][j]<<" ";
            }
            break ;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/10428699.html

时间: 2024-07-30 14:02:43

Codeforces Round #541 (Div. 2) 题解的相关文章

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces Round #259 (Div. 2) 题解

A. Little Pony and Crystal Mine time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Twilight Sparkle once got a crystal from the Crystal Mine. A crystal of size n (n is odd; n?>?1) is an n?×?n 

Codeforces Round #177 (Div. 2) 题解

[前言]咦?现在怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛,一般我报一个数字A,随便再拉一个人选一个数字B.然后开始做第A^B场.如果觉得机密性不高,来点取模吧.然后今天做的这场少有的AK了.(其实模拟赛只做完了4题,最后1题来不及打了) 等等,话说前面几题不用写题解了?算了,让我难得风光一下啦. [A] A. Polo the Penguin and Segments time limit per test 2 seconds mem

Codeforces Round #534 (Div. 2)题解

Codeforces Round #534 (Div. 2)题解 A. Splitting into digits 题目大意 将一个数字分成几部分,几部分求和既是原数,问如何分可以使得分出来的各个数之间的差值尽可能小 解题思路 将n分成n个1相加即可 AC代码 #include<cstring> #include<string> #include<iostream> #include<cstdio> using namespace std; int main

Codeforces Round #561 (Div. 2) 题解

Codeforces Round #561 (Div. 2) 题解 题目链接 A. Silent Classroom 水题. Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 105; int n; char s[N], t[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) { scanf(&q

Codeforces Round #608 (Div. 2) 题解

目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 程序 D. Portals 题意 做法 程序 E. Common Number 题意 做法 程序 结束语 Codeforces Round #608 (Div. 2) 题解 前言 题目链接:仅仅只是为了方便以题目作为关键字能查找到我的题解而已(逃 Codeforces 1271A Codeforce

Codeforces Round #617 (Div. 3) 题解

目录 Codeforces Round #617 (Div. 3) 题解 前言 A. Array with Odd Sum 题意 做法 程序 B. Food Buying 题意 做法 程序 C. Yet Another Walking Robot 题意 做法 程序 D. Fight with Monsters 题意 做法 程序 E1. String Coloring (easy version) 题意 做法 程序 E2. String Coloring (hard version) 题意 做法

[Codeforces Round #617 (Div. 3)] 题解 A,B,C,D,E1,E2,F

[Codeforces Round #617 (Div. 3)] 题解 A,B,C,D,E1,E2,F 1296A - Array with Odd Sum 思路: 如果一开始数组的sum和是奇数,那么直接YES, 否则:如果存在一个奇数和一个偶数,答案为YES,否则为NO 代码: int n; int a[maxn]; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen(