Codeforces Round #542(Div. 2) 题解

A. Be Positive    

直接找数组中正数和负数的个数即可。

#include "bits/stdc++.h"
using namespace std;
int main()
{
    int n;
    cin>>n;
    int a=0,b=0;
    int x;
    for (int i = 0; i < n; ++i) {
        scanf("%d",&x);
        if(x>0)a++;
        else if(x<0)b++;
    }
    n=(n+1)/2;
    if(a>=n)puts("1");
    else if(b>=n)puts("-1");
    else puts("0");
}

B. Two Cakes   

每个数字出现两次,记录他们的下标,第一个人走下标小的,另外一个走下标大的,这样可以保证路程最短。

#include "bits/stdc++.h"
using namespace std;
int a[200004];
int b[200004];
int main()
{
    int n;
    scanf("%d",&n);
    int x;
    memset(a,0, sizeof(a));
    memset(b,0, sizeof(b));
    for (int i = 1; i <= 2*n; ++i) {
        scanf("%d",&x);
        if(a[x]==0)a[x]=i;
        else {
            b[x]=i;
            if(a[x]>b[x])swap(a[x],b[x]);
        }
    }
    long long ans=0;
    a[0]=1,b[0]=1;
    for (int i = 1; i <= n; ++i) {
        ans+=abs(a[i]-a[i-1]);
        ans+=abs(b[i]-b[i-1]);
    }
    printf("%lld\n",ans);
}

C. Connect   

首先考虑最朴素的暴力做法,暴力枚举两个点建边然后跑bfs,复杂度o(n^6),显然不行。

因为水路不能走,所以预处理出从起点出发能到达的点,和从终点出发能到达的点,然后再枚举这两个集合中的点,可以剪掉一些情况,但是在极端情况下还是会T。

此时考虑两个集合点建边,长度最小的边一定是从这两个集合的边缘出发的,所以只需要维护两个集合的边缘的点即可,最坏情况复杂度O(n^4)。

#include "bits/stdc++.h"
using namespace std;
char mp[54][54];int n;int sx,sy,ex,ey;
int f[4][2]={0,1,1,0,0,-1,-1,0};
bool vis[54][54];
struct node
{
    int x,y;
};
bool inmp(int x,int y)
{
    return x>=1&&x<=n&&y>=1&&y<=n;
}
vector<node>st;//起点边缘集合
vector<node>ed;//终点边缘集合
void init()
{
    queue<node>q;
    q.push({sx,sy});
    memset(vis,0, sizeof(vis));
    while(!q.empty())
    {
        node t=q.front();q.pop();
        int ok=0;
        for (int i = 0; i < 4; ++i) {
            node now=t;
            now.x+=f[i][0];now.y+=f[i][1];
            if(!inmp(now.x,now.y))continue;
            if(vis[now.x][now.y])continue;
            else if(mp[now.x][now.y]=='0'){
                q.push(now);vis[now.x][now.y]=1;
            }
            else ok=1;//判断边缘
        }
        if(ok)st.push_back(t);
    }
    while(!q.empty())q.pop();
    q.push({ex,ey});
    memset(vis,0, sizeof(vis));
    while(!q.empty())
    {
        node t=q.front();q.pop();
        int ok=0;
        for (int i = 0; i < 4; ++i) {
            node now=t;
            now.x+=f[i][0];now.y+=f[i][1];
            if(!inmp(now.x,now.y))continue;
            if(vis[now.x][now.y])continue;
            else if(mp[now.x][now.y]=='0'){
                q.push(now);vis[now.x][now.y]=1;
            }
            else ok=1;//判断边缘
        }
        if(ok)ed.push_back(t);
    }
}
bool bfs(int x1,int y1,int x2,int y2)
{
    queue<node>q;
    memset(vis,0, sizeof(vis));
    q.push({sx,sy});
    while(!q.empty())
    {
        node t=q.front();q.pop();
        if(t.x==x1&&t.y==y1)
        {
            t={x2,y2};
        }
        if(t.x==ex&&t.y==ey)return 1;
        for (int i = 0; i < 4; ++i) {
            node now = t;
            now.x+=f[i][0];
            now.y+=f[i][1];
            if(!inmp(now.x,now.y))continue;
            if(vis[now.x][now.y])continue;
            if(mp[now.x][now.y]=='0'){
                q.push(now);
                vis[now.x][now.y]=1;
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d",&n);
    cin>>sx>>sy>>ex>>ey;
    for (int i = 1; i <= n; ++i) {
        scanf("%s",mp[i]+1);
    }
    int ans=1e9;
    init();
    for (int i = 0; i < st.size(); ++i) {
        for (int j = 0; j < ed.size(); ++j) {
            int xxx=(st[i].x-ed[j].x)*(st[i].x-ed[j].x)+(st[i].y-ed[j].y)*(st[i].y-ed[j].y);
            if(ans<=xxx)continue;
            if(bfs(st[i].x,st[i].y,ed[j].x,ed[j].y))
                ans=xxx;
        }
    }
    if(ans==1000000000)ans=0;
    printf("%d\n",ans);
}

D1 D2. Toy Train

因为只能单向行驶,所以最终答案一定是所有点中所需时间的最大值。

考虑其中某一个点p,p点有a颗糖,要运输完p点的糖果,至少需要跑a-1个周期+最后一颗糖果所需要的时间

那么此时time=(a-1)*n+min(b),b为从p到按方向离p点最近的糖果的终点的点,那么预处理离p点最近的点和p点的糖果数量即可。复杂度O(n^2)。

#include "bits/stdc++.h"
using namespace std;
int Num[5004];//糖果数量
int mini[5004];//最近的点的坐标
int ans[5004];
int main()
{
    int n,m;
    cin>>n>>m;
    int x,y;
    memset(mini,0x3f3f3f3f, sizeof(mini));
    memset(Num,0, sizeof(Num));
    for (int i = 0; i < m; ++i) {
        cin>>x>>y;
        if(y<x)y+=n;//因为只能单向运输
        Num[x]++;
        mini[x]=min(mini[x],y);
    }
    for (int i = 1; i <= n; ++i) {//枚举起点
        int sum=0;
        for (int j = 0; j < n; ++j) {//枚举从该起点开始的所有点
            int p=(i+j<=n?i+j:i+j-n);
            int num=j;
            if(Num[p]==0)continue;
            num+=(Num[p]-1)*n;
            num+=mini[p]-p;
            sum=max(sum,num);
        }
        ans[i]=sum;
    }
    for (int i = 1; i <= n; ++i) {
        printf("%d ",ans[i]);
    }
    puts("");
}

E. Wrong Answer

为了方便处理,设定n=2000。

将前1998个数全部置0,仅改变最后两个数。

设最后两个数为a,b且a为负数。即 0 0 0 0 0 0……a b

正确答案为 2000*(a+b),Alice的答案为b。

那么有

2000*(a+b)= b+k

\because [2000*(a+b)] mod 2000=0

\therefore (b+k)mod2000=0

[(b)mod2000+(k)mod2000]mod2000=0

\because \left | a[i] \right |<=1e6

\therefore b=1000000-(k)mod2000

a=(b+k)/2000-b

\because b\sqsubseteq (998000,1000000)

\therefore max((b+k)/2000)=500500<b

\therefore a<0

#include "bits/stdc++.h"
using namespace std;
int n,a[2004];

int main()
{
    int k;
    cin>>k;
    int a,b;
    b=1000000-k%2000;
    a=(k+b)/2000-b;
    printf("2000\n");
    for (int i = 0; i < 1998; ++i) {
        printf("0 ");
    }
    printf("%d %d\n",a,b);
}

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值