Manthan, Codefest 18 (rated, Div. 1 + Div. 2)

作天宿舍停电没有打成,今天补了一下题目。

A题,我读的题意是所有包的和应该是N,随手猜了个规律,果然不对。。。然后因为所有包是全用或全不用,感觉像时二进制,但总觉得这样所有包的和就不是N 了。。不是很明白。求一下数的二进制长度,过了。

B题,有两个操作,是一个数加1或减1,问你最少的操作次数,使得学列中位数是不是等于s。思考一下,发现只需要判断中位数和S的大小关系就行了。如果是小与,就从Mid往后找,找到第一大于等于S的数停止,把这个范围的数全部加到S就行了。
同理如果是大于,就从Mid往前找,找到第一个小于等于S的数停止。
代码如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 2e5+10;
typedef long long ll;
ll N,S;
ll a[MAX];
int main(void){
    scanf("%I64d%I64d",&N,&S);
    for(int i=1;i<=N;++i){
        scanf("%I64d",&a[i]);
    }
    ll Mid = N/2+1;
    sort(a+1,a+1+N);
    ll sum = 0;
    if(a[Mid] <= S){
        for(int i=Mid;i<=N;++i){
            sum += (S-a[i]);
            if(i != N && a[i] <= S && a[i+1] > S)
                break;
        }
        printf("%I64d\n",sum);
    }
    else{
        for(int i=Mid;i>=1;--i){
            sum += (a[i]-S);
            if(i != 1 && a[i] >= S && a[i-1] < S)
                break;
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

C题,感觉这个比B题简单点。给你两个二进制串s,t,你可以对s进行两种操作,一种交换i,j位置的数,代价为|i-j|,另一种把某个位置数取反代价为1。问你最小的代价使得s变为t。
很显然,只有相邻的两个会进行第一种操作,因为如果距离大于1,第一种操作不如第二种操作。直接扫描s,当某个位置不同,判断相邻的后一个位置是否不同,且与当前这个位置的t相同。就进行第一种操作,其他都进行第二种操作。

代码如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 1e6+10;
char a[MAX],b[MAX];
void filp(char &ch){
    if(ch == '0')
        ch = '1';
    else
        ch = '0';
}
int main(void){
    int N;
    scanf("%d",&N);
    scanf("%s",a+1);
    scanf("%s",b+1);
    int res = 0;
    for(int i=1;i<=N;++i){
        if(a[i] != b[i]){
            if(i == N){
                res++;
                filp(a[i]);
            }
            else{
                if(a[i+1] == b[i+1]){
                    res++;
                    filp(a[i]);
                }
                else{
                    if(a[i] == a[i+1]){
                        res++;
                        filp(a[i]);
                    }
                    else{
                        res++;
                        swap(a[i],a[i+1]);
                    }
                }
            }
        }
    }
    printf("%d\n",res);
  //  printf("%s\n",a+1);


    return 0;
}

D题:给你个树,在给你个序列,问你这个序列是不是bfs序列的一个结果。

这个题树是无向图,看错了。WA了好几次哎。。而且BFS序列和下一层序列和上一层的放入顺序也有关系。这里也要判断。

就是先把树分层,判断序列对应的是不是与该层相同,再对这层的孩子与对应序列判断。

感觉自己写的很麻烦
代码如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 2e5+10;
vector<int> G[MAX],lay[MAX];
int seq[MAX];
bool used[MAX];
set<int> son[MAX];
int top;
void bfs(){
    memset(used,false,sizeof(used));
    queue<int> que;
    top = 0;
    lay[top].push_back(1);
    top++;
    que.push(1);
    used[1] = true;
    while(!que.empty()){
        int u = que.front();que.pop();
        for(int i=0;i<G[u].size();++i){
            int v = G[u][i];
            if(!used[v]){
                used[v] = true;
                son[u].insert(v);
                lay[top].push_back(v);
            }
        }
        if(que.empty()){
            if(lay[top].size() != 0){
                for(int i=0;i<lay[top].size();++i){
                    que.push(lay[top][i]);
                }
                top++;
            }
        }
    }
}
bool Equal(vector<int> A,vector<int> B){
    sort(A.begin(),A.end());
    sort(B.begin(),B.end());
    if(A.size() != B.size())    return false;
    for(int i=0;i<A.size();++i)
        if(A[i] != B[i])
            return false;
    return true;
}
bool solve(){
    if(seq[1] != 1 )    return false;
    bfs();
    int l = 1,r = 1;
    for(int i=0;i<top;++i){
        r = l + lay[i].size();
        vector<int> vec;
        for(int j=l;j<r;++j)
            vec.push_back(seq[j]);
        if(!Equal(vec,lay[i]))  return false;
        l = r;
        if(i == top-1)  break;
        for(int j=0;j<vec.size();++j){
            int u = vec[j];
            vector<int> temp;
            for(int k=r;k<r+son[u].size();++k)
                temp.push_back(seq[k]);
            vector<int> ss;
            for(set<int>::iterator it = son[u].begin();it != son[u].end();++it){
                ss.push_back(*it);
            }
            if(!Equal(temp,ss))    return false;
            r += son[u].size();
        }
    }
    return true;
}
int main(void){
    int N;
    scanf("%d",&N);
    int u,v;
    for(int i=1;i<=N-1;++i){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i=1;i<=N;++i){
        scanf("%d",&seq[i]);
    }
    if(solve()) printf("Yes\n");
    else    printf("No\n");
    return 0;
}

/*
7
1 2
1 3
2 4
2 5
3 6
3 7
1 3 2 4 5 6 7

7
1 2
1 3
2 4
2 5
3 6
3 7
1 2 3 4 5 6 7
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值