【题解】北化2021年“蓝桥杯”研究生组校内选拔训练赛三

A 分数拆分

题目大意

       输入多组正整数k,找到所有的正整数x>=y,使得1/k=1/y+1/x,并按照y从大到小的顺序输出所有成立的分数式。

解题思路

       由于 k k k 的范围 1 ≤ k ≤ 100000 1≤k≤100000 1k100000,如果直接循环 [ 1 , 1 e 5 ] [1, 1e^5] [1,1e5] 遍历寻找符合条件的 x x x, y y y,会超过时限,所以要先对式子进行处理,过程如下:
1 k = 1 x + 1 y \frac 1k=\frac 1x+\frac 1y\\ k1=x1+y1
1 k = x + y x y \frac 1k=\frac {x+y}{xy}\\ k1=xyx+y
k = x y x + y ( x + y ) k = x y k x = ( x − k ) y k=\frac {xy}{x+y}\\ (x+y)k=xy\\ kx=(x-k)y\\ k=x+yxy(x+y)k=xykx=(xk)y

       处理好式子后,再确定 x x x 的可选范围, x , y x, y x,y 为正整数,所以 x x x 最小时 ( x − k ) > 0 (x-k)>0 (xk)>0 ;当 x = y x=y x=y 时达到 x x x 可取的最大值,所以 x x x 可选范围 [ k + 1 , 2 k ] [k+1,2k] [k+1,2k],遍历此范围寻找符合上式的正整数 y y y 即可。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
 
int main()
{
    LL k;
    while(scanf("%lld", &k) != EOF) {
        LL y;
        for(LL x = k + 1LL; x <= 2LL * k; x = x + 1LL) {
            LL res1 = k * x, res2 = x - k;
            if(res1 % res2 != 0LL) continue;
            y = res1 / res2;
            printf("1/%lld=1/%lld+1/%lld\n", k, y, x);
        }
    }
    return 0;
}

B 最大乘积

题目大意

       输入包括多组数据,每组数据第一行为正整数n,第二行为n个元素组成的序列S,你需要对每组数据找出一个乘积最大的连续子序列,如果这个最大的乘积不是正数,则输出-1。

解题思路

       数据范围小,暴力枚举题,复杂度 O ( n 2 ) O(n^2) O(n2),值得注意的是乘积结果可能会超过 int 范围,记得开 long long。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
LL a[50];
 
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        LL Max = a[1];
        for(int i = 1; i <= n; i++) {
            LL res = 1LL;
            for(int j = i; j <= n; j++) {
                res = res * a[j];
                Max = max(Max, res);
            }
        }
        if(Max <= 0LL) printf("-1\n");
        else printf("%lld\n", Max);
    }
    return 0;
}

C 求和

题目大意

       多组输入,每组给一个长度为n的序列,你需要求出其中连续m个数的和的最大值是多少。

解题思路

        前缀和问题。 n , m ∈ ( 0 , 1 e 5 ] n, m∈(0,1e^5] n,m(0,1e5],如果直接进行暴力枚举的话会时间超限。维护一个前缀和数组,那么从第 i i i 个数开始的连续 m m m 个数的和用 p r e [ i + m − 1 ] − p r e [ i − 1 ] pre[i + m - 1] - pre[i - 1] pre[i+m1]pre[i1] 即可解决,时间复杂度控制在了 O ( n ) O(n) O(n) 范围内。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MaxN = 1e5;
LL a[MaxN + 5], pre[MaxN + 5];
 
int main()
{
    int T; scanf("%d", &T);
    while(T--){
        int n, m; scanf("%d %d", &n, &m);
        for(int i = 0; i <= MaxN; i++) pre[i] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            if(i == 1) pre[i] = a[i];
            else pre[i] = pre[i - 1] + a[i];
        }
        LL Max = 0LL;
        for(int i = 1; i <= (n - m + 1); i++) {
            LL res = pre[i + m - 1] - pre[i - 1];
            Max = max(Max, res);
        }
        printf("%lld\n", Max);
    }
    return 0;
}

D 神奇炸弹

题目大意

       在一个二维空间中有 n 个点,已知每个点的 ( x , y ) (x,y) (x,y) 坐标和权值。现给定一个边长为 R 的正方形,其边与 x y 轴平行,任意放置正方形,求在正方形内能包含的最大权值是多少。

解题思路

       二维前缀和问题。前缀和数组 p r e [ i ] [ j ] pre[i][j] pre[i][j] 表示的是从 ( 0 , 0 ) (0, 0) (0,0) ( i , j ) (i, j) (i,j) 为顶点的矩形中的包含的权值和,那么如果求从 ( x x , y y ) (xx, yy) (xx,yy) ( i , j ) (i, j) (i,j) 为顶点的矩形中包含的权值和为:
p r e [ i ] [ j ] − p r e [ x x ] [ j ] − p r e [ i ] [ y y ] + p r e [ x x ] [ y y ] pre[i][j]-pre[xx][j]-pre[i][yy]+pre[xx][yy] pre[i][j]pre[xx][j]pre[i][yy]+pre[xx][yy] 如图所示,紫色区域的权值等于 黄色 - 红色 - 绿色 + 蓝色。
在这里插入图片描述

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MaxN = 5e3;
int n, r;
int a[MaxN + 5][MaxN + 5], pre[MaxN + 5][MaxN + 5];
 
int main()
{
    scanf("%d %d", &n, &r);
    int l = 5000;
    for(int i = 1; i <= n; i++) {
        int x, y, v; scanf("%d %d %d", &x, &y,&v);
        a[x][y] = v;
        pre[x + 1][y + 1] = v;
    }
 
    for(int i = 1; i <= l; i++) {
        for(int j = 0; j <= l; j++) {
            pre[i][j] = pre[i - 1][j] + pre[i][j];
        }
    }
    for(int i = 0; i <= l; i++) {
        for(int j = 1; j <= l; j++) {
            pre[i][j] = pre[i][j - 1] + pre[i][j];
        }
    }
/*
    for(int i = 0; i <= 10; i++) {
        for(int j = 0; j<= 10; j++){
            printf("%d ", pre[i][j]);
        }
        printf("\n");
    }
*/
    if(r >= l) printf("%d\n", pre[l][l]);
    else {
        int Max = 0;
        for(int i = r; i <= l; i++) {
            for(int j = r; j <= l; j++) {
                int xx = max(0, i - r), yy = max(0, j - r);
                int res = pre[i][j] - pre[xx][j] - pre[i][yy] + pre[xx][yy];
                Max = max(Max, res);
            }
        }
        printf("%d\n", Max);
    }
    return 0;
}

E 全排列问题

题目大意

       计算从1到N的N个整数所能构成的所有排列,并按照字典顺序依次输出。

解题思路

       灵活运用 n e x t _ p e r m u t a t i o n ( ) next\_permutation() next_permutation() 函数即可。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
int p[20];
 
int main()
{
    int n; 
    while(1) {
        scanf("%d", &n);
        if(n == 0) break;
        for(int i = 0; i < n; i++) p[i] = i + 1;
        do {
            for(int i = 0; i < n; i++) {
                printf("%d", p[i]);
                if(i == n - 1) printf("\n");
                else printf(" ");
            }
        }while(next_permutation(p, p + n));
 
    }
    return 0;
}

F 24点游戏

题目大意

       给出4个正整数操作数,你的任务是使用运算符(+,-,*,/)和括号对操作数进行计算,分析是否能得到24,每个操作数只能使用1次,运算符和括号可以多次使用,注意所有的中间结果都必须是整数。

解题思路

       模拟题。a_b_c_d 四个数进行运算,不考虑运算符到底是什么,首先确定括号可能出现的位置,也就是运算顺序:
       ① 先进行ab运算,再与c进行运算,最后与d进行运算:[(a_b)_c]_d
       ② 先进行ab运算,再进行cd运算,最后进行ab与cd运算:(a_b)_(c_d)
       ③ 先进行bc运算,再与a进行运算,最后与d进行运算:[a_(b_c)]_d
       ④ 先进行bc运算,再与d进行运算,最后与a进行运算:a_[(b_c)_d]
       ⑤ 先进行cd运算,再与b进行运算,最后与a进行运算:a_[b_(c_d)]
       运算顺序确定后,通过暴力枚举每个下划线位置可能出现的运算符以及abcd四个数的顺序,确定最终是否可以式子得到24。注意: 除法时要考虑到除数不能为 0 。
此外,递归方法同样可以解决这一问题。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
double a, b, c, d;
char op[] = {'+','-','*','/'};
double p[10];
 
 
double jisuan(double x, double y, char to) {
    if(to == '+') return x + y;
    if(to == '-') return x - y;
    if(to == '*') return x * y;
    if(to == '/') {
        if(y == 0) return INF;
        return x / y;
    }
}
 
 
int main()
{
    while(scanf("%lf %lf %lf %lf", &p[0], &p[1], &p[2], &p[3]) != EOF) {
        a = p[0], b = p[1], c = p[2], d = p[3];
        if(a == 0 && b == 0 && c == 0 && d == 0) break;
        int flag = 0;
 
        do{ 
            a = p[0], b = p[1], c = p[2], d = p[3];
            // [(a_b)_c]_d
            for(int i = 0; i < 4; i++) {
                for(int j = 0; j < 4; j++) {
                    for(int k = 0; k < 4; k++) {
                        double ans;
                        ans = jisuan(a, b, op[i]);
                        if(ans == INF) continue;
                        ans = jisuan(ans, c, op[j]);
                        if(ans == INF) continue;
                        ans = jisuan(ans, d, op[k]);
                        if(ans == INF) continue;
                        if(ans == 24) {
                            flag = 1;
                            break;
                        }
                    }
                    if(flag == 1) break;
                }
                if(flag == 1) break;
            }
            if(flag == 1) {
                printf("Yes\n");
                break;
            }
 
            // [a_(b_c)]_d
            for(int i = 0; i < 4; i++) {
                for(int j = 0; j < 4; j++) {
                    for(int k = 0; k < 4; k++) {
                        double ans;
                        ans = jisuan(b, c, op[j]);
                        if(ans == INF) continue;
                        ans = jisuan(a, ans, op[i]);
                        if(ans == INF) continue;
                        ans = jisuan(ans, d, op[k]);
                        if(ans == INF) continue;
                        if(ans == 24) {
                            flag = 1;
                            break;
                        }
                    }
                    if(flag == 1) break;
                }
                if(flag == 1) break;
            }
            if(flag == 1) {
                printf("Yes\n");
                break;
            }
 
            // a_[(b_c)_d]
            for(int i = 0; i < 4; i++) {
                for(int j = 0; j < 4; j++) {
                    for(int k = 0; k < 4; k++) {
                        double ans;
                        ans = jisuan(b, c, op[j]);
                        if(ans == INF) continue;
                        ans = jisuan(ans, d, op[k]);
                        if(ans == INF) continue;
                        ans = jisuan(a, ans, op[i]);
                        if(ans == INF) continue;
                        if(ans == 24) {
                            flag = 1;
                            break;
                        }
                    }
                    if(flag == 1) break;
                }
                if(flag == 1) break;
            }
            if(flag == 1) {
                printf("Yes\n");
                break;
            }
 
            // a_[b_(c_d)]
            for(int i = 0; i < 4; i++) {
                for(int j = 0; j < 4; j++) {
                    for(int k = 0; k < 4; k++) {
                        double ans;
                        ans = jisuan(c, d, op[k]);
                        if(ans == INF) continue;
                        ans = jisuan(b, ans, op[j]);
                        if(ans == INF) continue;
                        ans = jisuan(a, ans, op[i]);
                        if(ans == INF) continue;
                        if(ans == 24) {
                            flag = 1;
                            break;
                        }
                    }
                    if(flag == 1) break;
                }
                if(flag == 1) break;
            }
            if(flag == 1) {
                printf("Yes\n");
                break;
            }
 
            // (a_b)_(c_d)
            for(int i = 0; i < 4; i++) {
                for(int j = 0; j < 4; j++) {
                    for(int k = 0; k < 4; k++) {
                        double ans1 = jisuan(a, b, op[i]);
                        if(ans1 == INF) continue;
                        double ans2 = jisuan(c, d, op[k]);
                        if(ans2 == INF) continue;
                        double ans = jisuan(ans1, ans2, op[j]);
                        if(ans == INF) continue;
                        if(ans == 24) {
                            flag = 1;
                            break;
                        }
                    }
                    if(flag == 1) break;
                }
                if(flag == 1) break;
            }
            if(flag == 1) {
                printf("Yes\n");
                break;
            }
 
 
        }while(next_permutation(p, p + 4)); 
        if(flag == 0) printf("No\n");
    }
    return 0;
}

G 数数

题目大意

       给出一个数量为n的数列,你需要对每一个查询,回答出查询数在数列中的数量。

解题思路

       查询次数不超过 4 e 5 4e^5 4e5,数组长度不超过 1 e 5 1e^5 1e5 ,如果每次查询都遍历一遍数组会时间超限,所以在读入数组是预处理一个 map 存放当前值出现过几次,在每次查询的时候直接访问 map[x] 中的值即为 x 出现的次数。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MaxN = 1e5;
int a[MaxN + 5];
map<int, int>vis;
 
int main()
{
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        vis[a[i]]++;
    }
    int q; scanf("%d", &q);
    while(q--) {
        int x; scanf("%d", &x);
        printf("%d\n", vis[x]);
    }
    return 0;
}

H 销售排行榜

题目大意

       输入每行数据包括4个信息,分别是商品名称、销售数量、单价、成交日期,输出包括多行数据,将所有在输入中出现的商品按销售数量降序排列,每行数据包括3个信息,分别是商品名称、销售数量、销售额,如果两种商品销售数量一样,则按商品的字母顺序升序排列。

解题思路

       结构体排序经典问题。结构体中定义一个商品名,一个销售数量,一个总销售额和一个日期。创建一个以商品名为下标的 map ,当前商品在 map 中值为 0 时说明当前商品之前还没存在结构体中,此时添加当前商品信息到结构体中,并将当前商品在 map 中的值修改为在结构体中的下标;如果当前商品在 map 中的值非 0,则表示商品已经存在结构体中,调用 map 中的值并将该商品的相关信息更新。最后排序输出即可。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MaxN = 1e5;
map<string, int>vis;
struct node {
    string s;
    LL sum;
    LL cnt;
    string date;
}a[MaxN + 5];
 
bool cmp(node x, node y) {
    if(x.cnt == y.cnt) return x.s < y.s;
    return x.cnt > y.cnt;
}
 
int main()
{
    string ss, dd;
    LL cc, pp;
    int pos = 1;
    while(cin >> ss) {
        cin >> cc >> pp >> dd;
        if(vis[ss] == 0) {
            LL res = cc * pp;
            a[pos].s = ss, a[pos].cnt = cc, a[pos].sum = res, a[pos].date = dd;
            vis[ss] = pos;
            pos++;
        }
        else {
            int xx = vis[ss];
            LL res = cc * pp;
            a[xx].cnt += cc, a[xx].sum += res;
        }
    }
    sort(a + 1, a + pos, cmp);
    for(int i = 1; i < pos; i++) {
        cout << a[i].s << " " << a[i].cnt << " " << a[i].sum << " " << endl;
    }
    return 0;
}

I 有向图是否存在环

题目大意

       写程序判断有向图是否存在环。有向图的输入n个节点,m条边用m个二元组表示(u,v),表示从u到v有一条有向边,起点是u,终点是v。如果该有向图存在环,输出YES,否则输出NO。

解题思路

       经典图 dfs 问题。首先维护一个邻接矩阵 w [ i ] [ j ] = 1 w[i][j]=1 w[i][j]=1 表示从 i i i j j j 有一条有向边。接下来对每个点进行一次 dfs ,如果在 dfs 过程中某个点重复出现,则表示出现了环,否则继续对下一个节点进行 dfs。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MaxN = 100;
int w[MaxN + 5][MaxN + 5];
int s = 1, cnt = 0;
int n, m;
bool flag;
bool vis[MaxN + 5];
 
void dfs(int x) {
    cnt++;
//  printf("%d ", x);
    if(cnt != 1 && vis[x]) {
        flag = true;
        return;
    }
    vis[x] = 1;
    for(int i = 1; i <= n; i++) {
        if(w[x][i]) dfs(i);
    }
    return;
}
 
int main()
{
    while(scanf("%d %d", &n, &m) != EOF) {
        if(n == 0 && m == 0) break;
        for(int i = 0; i <= MaxN; i++) {
            vis[i] = 0;
            for(int j = 0; j <= MaxN; j++) w[i][j] = 0;
        }
        for(int i = 1; i <= m; i++) {
            int u, v; scanf("%d %d", &u, &v);
            w[u][v] = 1;
        }
        flag = false;
        for(int i = 1; i <= n; i++) {
            s = i, cnt = 0;
            dfs(i);
//          cout << "-----------------" << endl;
            if(flag == true) break;
            for(int i = 1; i <= n; i++) vis[i] = 0;
        }
        if(flag == true) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

J Maximum value

题目大意

       输入三个数a, b, c,输出最大的数是多少。

解题思路

       简单题。直接判断即可。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
 
int main()
{
    int a, b, c; scanf("%d %d %d", &a, &b, &c);
    int Max = a;
    Max = max(Max, b);
    Max = max(Max, c);
    printf("%d\n", Max);
 
    return 0;
}

END


以上仅代表个人想法,如有错误,请及时沟通指正,谢谢!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值