第九届蓝桥杯C/C++ 大学B组省赛编程题题目及答案解析

目录

试题F:递增三元组

试题G:螺旋折线

试题H:日志统计

试题I:全球变暖

试题J:乘积最大


试题F:递增三元组

【问题描述】

在这里插入图片描述

【输入格式】

在这里插入图片描述

【输出格式】

一个整数表示答案

【样例输入】

在这里插入图片描述

【样例输出】

27

【代码解析】

暴力:三重循环计算所有满足ai < bj < ck的数,时间复杂度为O(n^{3}),只能通过一半的数据。

排序+二分:对于a,b,c数组进行排序。枚举每一个bj,利用二分思想,求出满足bj > ai的最大下标i,则比bj小的a的元素的数量为i + 1,同理求出满足bi < ck的最小下标k,则比bj大的c的元素的数量为n - k,即对于bj存在 (i + 1) * (n - k)种方案满足题意。时间复杂度为O(nlogn),可以通过所有数据

前缀和:和第二种方法思路一样,运用前缀和的思想求比bi小的a的元素的数量及比bi大的c的元素的数量。时间复杂度为O(n),可以通过所有数据。

​排序+二分
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

int a[N], b[N], c[N];


int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < n; i ++) cin >> a[i];
    for(int i = 0; i < n; i ++) cin >> b[i];
    for(int i = 0; i < n; i ++) cin >> c[i];
    
    sort(a, a + n);
    sort(b, b + n);
    sort(c, c + n);
    LL res = 0;
    
    for(int i = 0; i < n; i ++)
    {
        LL l = 0, r = n - 1, n1 = 0, n2 = 0;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(a[mid] < b[i]) l = mid;
            else r = mid - 1;
        }
        if(a[r] < b[i]) n1 = r + 1;
        l = 0, r = n - 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(c[mid] > b[i])   r = mid;
            else l = mid + 1;
        }
        if(c[r] > b[i]) n2 = n - r;
        res += (LL)n1 * n2;    
    }
    cout << res;
    return 0;
}

​
​
前缀和
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;

typedef long long LL;

int a[N], b[N], c[N];
int cnt[N], as[N], cs[N], s[N];

int n;

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]), a[i] ++;
    for(int i = 0; i < n; i ++) scanf("%d", &b[i]), b[i] ++;
    for(int i = 0; i < n; i ++) scanf("%d", &c[i]), c[i] ++;

    for(int i = 0; i < n; i ++) cnt[a[i]] ++;
    for(int i = 1; i < N; i ++) s[i] = s[i - 1] + cnt[i];
    for(int i = 0; i < n; i ++) as[i] = s[b[i] - 1];

    memset(s, 0, sizeof s);
    memset(cnt, 0, sizeof cnt);

    for(int i = 0; i < n; i ++) cnt[c[i]] ++;
    for(int i = 1; i < N; i ++) s[i] = s[i - 1] + cnt[i];
    for(int i = 0; i < n; i ++) cs[i] = s[N - 1] - s[b[i]];

    LL res = 0;
    for(int i = 0; i < n; i ++)
    {
        res += (LL)as[i] * cs[i];
    }
    cout << res;
    return 0;
}

​

​

试题G:螺旋折线

【问题描述】

在这里插入图片描述

 

【输入格式】

在这里插入图片描述

【输出格式】

输出dis(X, Y)

【样例输入】

0 1

【样例输出】

3

【代码解析】

 模拟 + 找规律,时间复杂度为O(1),注意输出的数据量可能会爆int范围,记得开long long来存。

​
#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long LL;

int main()
{
    int x, y;
    cin >> x >> y;
    if(abs(x) <= y)
    {
        int n = y;
        cout << (LL)(2 * n) * (2 * n - 1) + x - (- n) << endl; 
    }
    else if(x >= abs(y))
    {
        int n = x;
        cout << (LL)(2 * n) * (2 * n) + n - y << endl;
    }
    else if(abs(y) + 1 >= abs(x) && y < 0)
    {
        int n = abs(y);
        cout << (LL)(2 * n) * (2 * n + 1) + n - x << endl;
    }
    else
    {
        int n = abs(x);
        cout << (LL)(2 * n - 1) * (2 * n - 1) + y - (- n + 1) << endl;
    }
    return 0;
}

​

试题H:日志统计

【问题描述】

在这里插入图片描述

【输入格式】

在这里插入图片描述

【输出格式】
按从小到大的顺序输出热帖id。每个id一行。

1
2
3
4
5
6
7
8
9
【输入样例】

7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

【输出样例】

1
3

【代码解析】

 模拟题,用排序+双指针

1、对所有的赞按照时间从小到大排序

2、通过双指针i,j维护长度不大于d的区间,并记录该区间的中所有帖子获得的赞数 

​
#include <iostream>
#include <cstring>
#include <algorithm>

#define x first
#define y second

using namespace std;

const int N = 1e5 + 10;

typedef pair<int, int> PII;

PII logs[N];
bool st[N];
int cnt[N];

int n, d, k;

int main()
{
    scanf("%d%d%d", &n, &d, &k);
    for(int i = 0; i < n; i ++)
    {
        int ts, id;
        scanf("%d%d", &ts, &id);
        logs[i] = {ts, id};
    }
    sort(logs, logs + n);

    for(int i = 0, j = 0; i < n; i ++)
    {
        int id = logs[i].y;
        cnt[id] ++;
        while(logs[i].x - logs[j].x >= d)
        {
            cnt[logs[j].y] --;
            j ++;
        }

        if(cnt[id] >= k)    st[id] = true;
    }

    for(int i = 0; i < N; i ++) if(st[i])   cout << i << endl;
    return 0;
}

​

试题I:全球变暖

【问题描述】
你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:
在这里插入图片描述

【输入格式】

第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。

照片保证第1行、第1列、第N行、第N列的像素都是海洋。

请你计算:依照科学家的预测,照片中会有多少岛屿会被完全淹没。

【输出格式】

一个整数表示答案。
1
2
3
4
5
6
7
8

【输入样例】

7

.##…
.##…
…##.
…####.
…###.

【输出样例】

1

【代码解析】

遍历所有未遍历过的陆地,通过bfs计算出当前位置连通陆地的数量total,以及被淹没陆地的数量bound,若total == bound表示完整淹没的一个岛屿

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

char g[N][N];
bool st[N][N];

int n;

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

void bfs(int i, int j, int &total, int &bound)
{
    queue<PII> q;
    st[i][j] = true;
    q.push({i, j});
    
    while(q.size())
    {
        total ++;
        bool is_bound = false;
        auto t = q.front();
        q.pop();
        for(int i = 0; i < 4; i ++)
        {
            int x = t.x + dx[i], y = t.y + dy[i];
            if(x < 0 || x >= n || y < 0 || y >= n)  continue;
            if(!st[x][y] && g[x][y] == '#')
            {
                st[x][y] = true;
                q.push({x, y});
            }
            if(g[x][y] == '.')
                is_bound = true;
        }
        if(is_bound == true) bound ++;
    }
    
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++) cin >> g[i];
    
    int cnt = 0;
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < n; j ++)
        {
            if(g[i][j] == '#' && !st[i][j])
            {
                int bound = 0;
                int total = 0;
                bfs(i, j, total, bound);
                if(total == bound)  cnt ++;
            }
        }
    cout << cnt;
    return 0;
}

试题J:乘积最大

【问题描述】

在这里插入图片描述

【输入格式】

在这里插入图片描述

【输出格式】

一个整数,表示答案。
1
2
3
4
5
6
7
8
9
10
【输入样例】

5 3
-100000
-10000
2
100000
10000

【输出样例】

999100009
1
2
3
4
5
6
7
8
9
10
再例如:
【输入样例】

5 3
-100000
-100000
-2
-100000
-100000

【输出样例】

-999999829

【代码解析】

分类讨论+贪心:

情况1:n == k,求出数据的乘积取模即可。

情况2:n < k && k为偶数,分析可知,不论数据如何,总能取到数据的乘积为正数。

情况3:n < k && k为奇数 && 数据不全为负数,分析可知,先取最大的数据,此时即可转换为情况2继续进行操作。

情况4:n < k && k为奇数 && 数据全为负数,分析可知,此时无论如何取,最终答案必为负数,这时我们的贪心思路为先取最大的数据,之后取的k - 1个数据保证其乘积最小,即可求出最大的乘积。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const LL mod = 1000000009;

const int N = 1e5 + 10;

int a[N];

int n, m;

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    sort(a, a + n);
    int i = 0, j = n - 1, sign = 1;
    LL sum = 1;
    if(m % 2)
    {
        sum *= a[j] % mod;
        if(a[j] < 0)    sign = -1;
        j --;
        m --;
    }
    while(m)
    {
        if((LL)a[i] * a[i + 1] * sign >= (LL)a[j] * a[j - 1] * sign)
        {
            sum = sum * a[i] % mod * a[i + 1] % mod;
            i += 2;
            m -= 2;
        }
        else
        {
            sum = sum * a[j] % mod * a[j - 1] % mod;
            j -= 2;
            m -= 2;
        }
    }
    if(sum > 0)
        cout << sum % mod;
    else
        cout << 0-((0-sum)%mod);
    return 0;
    
}

最后大家有疑问的话可以评论区留言讨论,第一次写博客,有写的不好的地方,不清楚的地方还请多多包涵指正。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值