3.14 BAPC 2019

Posted liucongcong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.14 BAPC 2019相关的知识,希望对你有一定的参考价值。

A: Architecture

题意:给定第一行的值表示 m 列的最大值,第 m 行的值表示 n 行的最大值,问是否会
行列冲突。
思路:求出行列最大值,如果相同则输出 possible,否则 impossible。

简单来说 就是求这两行数各自的最大值,看它们是否相等

#include<stdio.h>
int main(){
    int r,c,i,j,a[100],b[100],ma,mb;
    scanf("%d%d",&r,&c);
    for(i=0;i<r;i++){
        scanf("%d",&a[i]);
    }
    for(j=0;j<c;j++){
        scanf("%d",&b[j]);
    }
    ma=a[0];
    mb=b[0];
    //printf("%d %d ",ma,mb);
    for(i=1;i<r;i++){

            if(a[i]>ma){
                ma=a[i];
            }

    }
    for(i=1;i<c;i++){

            if(b[i]>mb){
                mb=b[i];
            }

    }
   // printf("%d %d ",ma,mb);
    if(ma==mb){
        printf("possible ");
    }else{
        printf("impossible ");
    }
}

B. Bracket Sequence

题解:给定一字符串,最外层数字之间全用+,一层括号用*,两层用+,三层用*,以此
类推。
Solve1: 每一层括号里的数字之间使用的符号相同,用栈存每一层的数字计算即可,需要手写栈,否则空间不够。

Solve2: 栈中记录使用 * 或者 + ,遇到非‘(’计算即可。

这个题我没有做出来,献出大佬的题解

/*
给你一串字符串,最外面全用+,一层括号用*,两层用+,三层用*,以此类推
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const long long mod = 1e9 + 7;

int n;
char s[15];

struct node
{
    int val;
    node* next;
    node(int w, node *n){
        val = w;
        next = n;
    }
};

class Stack{
public :
    int sz;
    node* head;
    
    Stack(){
        head = NULL;
        sz = 0;
    }
    bool empty(){
        return !sz;
    }
    int top(){
        if(!empty()) return head->val;
        return 0;
    }
    node *push(int val){
        head = new node(val, head);
        sz++;
        return head;
    }
    void pop(){
        if(empty()) return ;
        node *tp = head;
        head = head->next;
        sz--;
        delete tp;
    }
    int size(){
        return sz;
    }
}sk[300005];

int change(char s[]){
    int res = 0;
    int len = strlen(s);
    for (int i = 0; i < len; i++) res = res * 10 + s[i] - ‘0‘;
    return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    int cnt = 0;
    for (int i = 1; i <= n; i++){
        scanf("%s", s);
        if(s[0] == ‘(‘) cnt++;
        else if(s[0] == ‘)‘){
            if(cnt & 1){
                LL ans = 1;
                while(sk[cnt].size()) ans = ans * sk[cnt].top() % mod, sk[cnt].pop();
                cnt--;
                sk[cnt].push(ans);
            }else{
                LL ans = 0;
                while(sk[cnt].size()) ans = (ans + sk[cnt].top()) % mod, sk[cnt].pop();
                cnt--;
                sk[cnt].push(ans);
            }
        }else{
            sk[cnt].push(change(s));
        }
    }
    LL ans = 0;
    while(sk[0].size()) ans = (ans + sk[0].top()) % mod, sk[0].pop();
    printf("%lld ", ans);

    return 0;
}
/**/

C. Canyon Crossing

题解:可建 k 座桥,建桥后山的高度忽略不计,求从底部(第 r 行)走到顶部(第 1 行)的
路线中最小值最大是多少。
思路:二分答案,用 bfs 跑图即可,因为每一个单元格会重复走,对于走的距离循环来优化 bfs。

题解题解,不是我的代码

/*
现在可以建k座桥,建桥后山的高度忽略不计
求从底部走到顶部的路线中最小值最大是多少
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, m, k;
int mp[1005][1005];
bool vis[1005][1005];
int d[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};

struct node
{
    int x, y;
    node() {}
    node(int x, int y) : x(x), y(y) {}
};

int bfs(int val){
    memset(vis, 0, sizeof(vis));
    queue<node> q[k + 2];
    for (int i = 1; i <= m; i++) vis[n][i] = true, q[mp[n][i] < val ? 1 : 0].push(node(n, i));
    for (int i = 0; i <= k; i++){
        while(q[i].size()){
            node front = q[i].front();
            if(front.x == 1) return 1;
            q[i].pop();
            for (int j = 0; j < 4; j++){
                int x = front.x + d[j][0], y = front.y + d[j][1];
                if(x < 1 || x >= n || y < 1 || y > m) continue;
                if(!vis[x][y]){
                    vis[x][y] = true;
                    q[mp[x][y] < val ? i + 1 : i].push(node(x, y));
                }
            }
        }
    }

    return 0;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    int l = 0, r = 0;
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            scanf("%d", &mp[i][j]);
            r = max(r, mp[i][j]);
        }
    }
    int ans = l;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(bfs(mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%d ", ans);

    return 0;
}
/**/

D. Deceptive Dice

题意:有一个 n 面的骰子,现在最多可以玩 k 轮,如果在 i(i<=k)轮达到了期望水平(即
期望的骰子分数),那么就会终止,否则继续,问最终游戏的期望分数。
求出第 i 轮的期望分数为 socre1,对于第 i + 1 轮来说,进行第 i + 1 轮
的条件是第 i 轮没有到达期望分数 score1,那么第 i + 1 轮的期望分数为。

题解题解,不是我的代码

/*
有一个n面的骰子,现在最多可以玩k轮
如果在i(i<=k)轮达到了期望水平,那么就会终止,否则继续
问最终游戏的期望分数
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
 
typedef long long LL;
using namespace std;
 
int n, k;
int p[10005];
 
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
 
    scanf("%d %d", &n, &k);
    double ans = 0;
    for (int i = n; i >= 1; i--) p[i] = p[i + 1] + i;
    for (int i = 1; i <= k; i++){
        if(i == 1){
            ans = 1.0 * p[i] / n;
        }else{
            ans = 1.0 * (p[(int)floor(ans) + 1] + floor(ans) * ans) / n;
        }
    }
    printf("%.7lf ", ans);
 
    return 0;
}
/**/

E. Exits in Excess
题意:移除最多一半的边使得图没有环。
思路:将所有边分成两部分,第一部分为 u < v,第二部分为 v > u,将小的边集合删去。

题解题解,不是我的代码

/*
移除最多一半的边使得图没有环
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, m;

vector<int> v1, v2;

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d %d", &n, &m);
    for (int i = 1, u, v; i <= m; i++){
        scanf("%d %d", &u, &v);
        if(u < v) v1.push_back(i);
        else v2.push_back(i);
    }
    if(v1.size() > v2.size()){
        printf("%d ", v2.size());
        for (auto x : v2) printf("%d ", x);
    }else{
        printf("%d ", v1.size());
        for (auto x : v1) printf("%d ", x);
    }

    return 0;
}
/**/

F. Floor Plan

题意:给定 n, 求 n=m^2-k^2。

我的解决思路就是一个个的遍历,结果超时了,想了半天也没想出来啥好方法

看一下我的代码,这个是错的哈!错的!错的!

运行没错!结果没错!但是是超时的!

#include<stdio.h>
#include<math.h>
int main(){
    int n,m,k;
    scanf("%d",&n);
    for(m=sqrt(n);m<n;m++){
        for(k=0;k<m;k++){
            if(n==m*m-k*k){
                printf("%d %d ",m,k);
                break;
            }
        }

        if(k<m){
            break;
        }
    }
    if(m>=n){
        printf("impossible ");
    }
}
接下来

看一下题解

思路:
1. 对于 n 为奇数时,有(x+1)^2-x^2=2x+1。
2. 对于 n 为 4 的倍数时,有(x+2)^2-x^2=4(x+1)。
3. Impossible。
证明:
若 n % 2 == 0 且 n % 4 != 0,n = (m - k)(m + k),
∵n 为偶数,
∴(m - k)或者(m + k)必有一项是偶数,若(m-k)是偶数,那么(m+k)也是偶数,反之同理。

代码:

/*
给你n, 求n = m * m - k * k
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

LL n;

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%lld", &n);
    if(n & 1) printf("%lld %lld ", n / 2 + 1, n / 2);
    else if(n % 2 == 0 && n % 4) printf("impossible ");
    else printf("%lld %lld ", (n - 4) / 4 + 2, (n - 4) / 4);

    return 0;
}
/**/

G. Greetings!

题意:输入,h开头,y结尾,e在中间的字符串,然后输出的时候中间的e的数量要加倍

思路:计算一下输入字符串的长度,减二再乘二就是要输出的e的个数

代码:

#include<stdio.h>
#include<string.h>
char a[1000];
int main(){
    int i,len;

    gets(a);
        len=strlen(a);
        printf("h");
        for(i=0;i<2*(len-2);i++){
            printf("e");
        }
        printf("y ");

}


H. Hexagonal Rooks

题意:给定起始位置的行(数字 1~11)和列(字母 a~k)和末位置的行和列,求两步(一步的
长度不一定是 1)走到末位置的中间点的数量。
思路:枚举所有棋的格子,同时满足从起始位置一步到所枚举的格子和所枚举的格子一步到末位置即答案 + 1。

题解题解,不是我的代码

/*
给你起始位置和末位置,求两步(一步的长度不一定是1)走到末位置的中间点的数量
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

char c1, c2;
int x, y;

bool solve(char sl, int sr, char el, int er){
    if(sl == el) return sr != er;
    if(sl > ‘f‘) sr += sl - ‘f‘;
    if(el > ‘f‘) er += el - ‘f‘;
    if(sr == er) return true;
    if(el - sl == er - sr) return true;
    return false;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%c%d %c%d", &c1, &x, &c2, &y);
    int ans = 0;
    for (int i = ‘a‘; i <= ‘k‘; i++){
        int num = 11 - abs(‘f‘ - i);
        for (int j = 1; j <= 11; j++){
            if(j > num) break;
            if(solve(c1, x, i, j) && solve(i, j, c2, y)) ans++;
        }
    }
    printf("%d ", ans);

    return 0;
}
/**/

I.Inquiry I

题意:给定数组 a,求公式的最大值。数组中的元素就是未知数的值,然后按照公式计算,求出其中的最大值。

思路:就按公式算就行

先看一下我的代码 这是错的昂!错的!错的!

样例过了,但是不太对!

#include<stdio.h>

int main(){
    int a[100],c[100];
    int i,j,k,sum,num,max,n;
    scanf("%d",&n);
    max=0;
    if(n>=2){
        for(k=0;k<n;k++){
            sum=num=0;
            for(i=k;i>=0;i--){
                sum+=a[i]*a[i];
            }
            for(j=k+1;i<n;j++){
                num+=a[j];
            }
            if(sum*num>max){
                max=sum*num;
            }
        }
        printf("%d ",max);
    }
}

再来看一下题解

/*
求公式最大值
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, a[1000005];
LL l[1000005], r[1000005];

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++) l[i] = l[i - 1] + a[i] * a[i];
    for (int i = n; i >= 1; i--) r[i] = r[i + 1] + a[i];
    LL ans = 0;
    for (int i = 1; i < n; i++) ans = max(ans, l[i] * r[i + 1]);
    printf("%lld ", ans);

    return 0;
}
/**/

K. Knapsack Packing

题意:给定 n 件物品和他们的重量以及所有组合重量,求是否存在这 n 件物品的重量
来满足这些组合。
思路:将所有重量存入 multiset 中,每次考虑最大的次大的,必能得到 n 个物
品中一个物品的重量,从 multiset 中删除与此重量有关的所有组合,若找不到,输出 impossible。

/*
给你n件物品和他们的重量和所有组合,求是否存在这n件物品的重量,满足这些组合
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n, ans[25];

multiset<int> s;

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    for (int i = 0, x; i < (1 << n); i++) scanf("%d", &x), s.insert(x);
    int cnt = 0;
    for (int i = 1; i <= n; i++){
        if(s.size() < 2) break;
        cnt++;
        int x = *prev(s.end()) - *prev(prev(s.end()));
        ans[i] = x;
        for (auto it = s.begin(); it != s.end(); it++){
            int y = *it;
            auto p = s.upper_bound(x + y);
            p = prev(p);
            if(p == s.end() || p == it || *p != x + y){
                printf("impossible ");
                return 0;
            }
            s.erase(p);
        }
    }
    if(s.size() != 1 || *s.begin() != 0 || cnt < n) printf("impossible ");
    else for (int i = 1; i <= n; i++) printf("%d ", ans[i]);

    return 0;
}
/**/

L. Lifeguards
题意:两个救生员中最靠近游泳者是监控者。找到两个救生员的坐标,使得救生员监控
的游泳者数量相同,最多有一个游泳的离两个救生员距离相同。
思路 :同 https://ac.nowcoder.com/acm/contest/883/H,将所有游泳的根据坐
标排序,用一直线划分成两部分,线的两个无穷远处为端点,若游泳的数量为奇
数,那么此线需经过中间点。设中间点为(x,y)Max 设为无穷大例: n 为偶数 (x -
Max, y - 1), (x + Max, y) n 为奇数 (x - Max, y - 1), (x + Max, y + 1)

题解题解,不是我的代码

/*
教练管理范围为:学员离的最近的一个教练
使得教练管理学员数量相同,最多有一个人离两个教练距离相同
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int n;
struct node
{
    LL x, y;
    bool operator <(const node &rhs)const{
        return x == rhs.x ? y < rhs.y : x < rhs.x;
    }
}a[100005];

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%lld %lld", &a[i].x, &a[i].y);
    sort(a + 1, a + 1 + n);
    int mid = (n + 2) / 2;
    LL MAX = 10000000000LL;
    LL x = a[mid].x, y = a[mid].y;
    // 必须一上一下 因为如果两个都在下面,那么会使得垂直x轴的直线上的点到两点的距离相同,或者会属于另一边
    if(n & 1){
        printf("%lld %lld ", x - MAX, y - 1);
        printf("%lld %lld ", x + MAX, y + 1);
    }else{
        printf("%lld %lld ", x - MAX, y - 1);
        printf("%lld %lld ", x + MAX, y);
    }

    return 0;
}
/**/

 

以上是关于3.14 BAPC 2019的主要内容,如果未能解决你的问题,请参考以下文章

2020年3月14日 BAPC2019 比赛补题报告

2020年3月21日 BAPC 2019 比赛补题报告

2020.03.14 Preliminaries for BAPC 2019 解题报告

BAPC 2014 Preliminary

Collatz Conjecture(BAPC2017)

BAPC 2014 Preliminary D