Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) 题解

Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)

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

A. Be Positive

题意:

给出n个数,看是否正数的个数过半或者负数的个数过半。

 

题解:
水题,代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n;
double a[N];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    int cnt1 = 0,cnt2=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]>0) cnt1++;
        else if(a[i]<0) cnt2++;
    }
    if(cnt1>=(n+1)/2) cout<<1;
    else if(cnt2>=(n+1)/2) cout<<-1;
    else cout<<0;
    return 0;
}
View Code

 

B. Two Cakes

题意:

给出2*n个商店,每个商店有其序号1,2...n,每个序号两个商店共有。现在有两个人想要买东西,但只能按照序号来买,从1买到n。

他们一开始的位置在最左边,问移动的距离总和最小是多少。

 

题解:

记录一下序号和位置,然后贪心就行了。

具体见代码吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n;
struct Node{
    int val,id;
    bool operator < (const Node &A)const{
        return val<A.val;
    }
}a[N];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n;
    for(int i=1;i<=2*n;i++){
        cin>>a[i].val;
        a[i].id=i;
    }
    sort(a+1,a+2*n+1);
    ll ans = 0;
    ans+=a[1].id+a[2].id-2;
    for(int i=3;i<=2*n;i+=2){
        ans+=min(abs(a[i].id-a[i-1].id)+abs(a[i+1].id-a[i-2].id),abs(a[i].id-a[i-2].id)+abs(a[i+1].id-a[i-1].id));
    }
    cout<<ans;
    return 0;
}
View Code

 

C. Connect

题意:

给出n*n的矩阵、起点以及终点,每个格子有0或者1,0代表陆地,1代表水。现在有个人想从起点走到终点,但他不能沾水。现在你可以修最多一条管道,连接两块陆地,费用为相应两点间距离的平方。问最终最小的费用为多少。

 

题解:

由于n最多只有50,所以可以直接采用很暴力的方法:先求出连通块,然后对起点和终点所在的连通块暴力枚举,最后求最小值。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int n,cnt;
int r1,c1,r2,c2;
char mp[N][N];
int vis[N][N],bel[N][N];
struct Node{
    int x,y;
};
int dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};
bool ok(int x,int y){
    return x>=1&&y>=1&&x<=n&&y<=n&&mp[x][y]=='0'&&!vis[x][y];
}
void bfs(int x,int y,int t){
    queue <Node> q;
    q.push(Node{x,y});
    vis[x][y]=1;
    while(!q.empty()){
        Node now=q.front();q.pop();
        int x=now.x,y=now.y;
        bel[x][y]=t;
        for(int i=0;i<4;i++){
            int curx=x+dx[i],cury=y+dy[i];
            if(ok(curx,cury)){
                vis[curx][cury]=1;
                q.push(Node{curx,cury});
            }
        }
    }
}
int dis(int x1,int y1,int x2,int y2){
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int main(){
    cin>>n>>r1>>c1>>r2>>c2;
    for(int i=1;i<=n;i++){
        scanf("%s",mp[i]+1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(mp[i][j]=='0'&&!vis[i][j]){
                bfs(i,j,++cnt);
            }
        }
    }
    int block1=bel[r1][c1],block2=bel[r2][c2];
    if(block1==block2){
        cout<<0;
        return 0;
    }
    int ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(mp[i][j]=='1') continue ;
            if(bel[i][j]==block1){
                for(int p=1;p<=n;p++){
                    for(int q=1;q<=n;q++){
                        if(mp[p][q]=='1') continue ;
                        if(bel[p][q]==block2){
                            ans=min(ans,dis(i,j,p,q));
                        }
                    }
                }
            }
        }
    }
    cout<<ans;
    return 0;
}
View Code

 

D2. Toy Train

题意:

给出一个环,有一辆火车从某个位置出发,不断绕着环走。然后有m个糖果需要火车运送,每次火车在一个站只能装配一个糖果,但可以同时卸下多个糖果。

最后输出火车从所有位置出发,并且将所有的糖果都配送完的最小时间。

 

题解:

这题还是挺有意思的,如果考虑中间过程,那么这个题目将会变得很麻烦。

其实最终会发现,如果我们选定了最后一个需要运送的糖果,那么答案就是固定的。因此我们可以直接枚举火车运送最后一颗糖果的时候从哪里出发就行了。

这里最后维护答案的时候要取max,稍微想下就知道了。

代码如下:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 5005;
int n,m;
vector <int> g[N];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
    }
    for(int i=1;i<=n;i++){
        int ans = 0,tot;
        for(int j=1;j<=n;j++){
            int num = g[j].size();
            if(num==0) continue ;
            tot=INF;
            for(auto v:g[j]){
                tot=min(tot,(num-1)*n+(j-i+n)%n+(v-j+n)%n);
            }
            ans=max(ans,tot);
        }
        cout<<ans<<" ";
    }
    return 0;
}
View Code

这个题还可以优化一波,就是不挨个从vector里面找,可以事先预处理一下从当前位置出发最短的距离是多少,然后根据这个来算就行了。

 

E. Wrong Answer

题意:

构造题,这里有一段代码:它只会记录和为非负数的一段数乘以其区间长度的最大值,但我们现在要求的是sum{ai}*(r-l+1),l<=i<=r,很明显这段代码是有错误的。

然后会输入一个k,你构造一组数据,使得正解和这段代码给出的答案相差k。最后输出你给出的数据。

 

题解:

这也是一个挺有意思的构造题吧,构造方法有很多,我说下我这个吧:

首先找到一个v,满足(k+v)%n==0,然后我们就想让我们构造出来的n个数的和为(k+v)/n,那么正解现在就应该是k+v了。

现在我们就只需要让有毒的代码得到v就行了。现在设出a,b两个数,其中a=v,那么(k+v)/n=a+b,这里我们算出b的值且b为负数就好了,那么最终的a,b就是我们需要构造的数。

具体构造方法为0,0,0,......b,a。这里一共有2000个数,b在前面可以使得有毒的代码得到a(也就是v),同时正确答案是k+v。那么此时就满足条件了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int k,v,a,b;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>k;
    int n=2000;
    v=1;
    while(1){
        int f1=0,f2=0;
        if((k+v)%n==0) f1=1;
        if(f1&&(k+v)/n-v<0) f2=1;
        if(f1&&f2) break ;
        v++;
    }
    a=v;
    b=(k+v)/n-a;
    cout<<n<<endl;
    for(int i=1;i<=n-2;i++) cout<<0<<" ";
    cout<<b<<" "<<a;
    return 0;
}
View Code

 

posted @ 2019-02-25 18:59  heyuhhh  阅读(314)  评论(0编辑  收藏  举报