buctoj——2024寒假集训 进阶训练赛 (五)

发布时间:2024年01月23日

问题 A: 约瑟夫问题

题目描述
N个人围成一圈,从第一个人开始报数,数到M的人出圈;再由下一个人开始报数,数到M的人出圈;……输出依次出圈的人的编号。N,M由键盘输入。
输入
一行,包含两个正整数N,M。1<=N,M<=100。
输出
先输出一个空行,再依次出圈的人的编号。每个编号后都有一个空格。
样例输入

8 5

样例输出


5 2 8 7 1 4 6 3 

思路
利用队列先进先出的特性,模拟数数的过程,将数到m的人出列,其余人再排到队尾。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;

void solve()
{
    int n, m;
    cin >> n >> m;
    cout << endl;
    queue<int> q;
    for (int i = 1; i <= n; i ++ ){
        q.push(i);
    }
    while(q.size()){
        for (int i = 1; i < m; i ++ ){
            int t = q.front();
            q.pop();
            q.push(t);
        }
        cout << q.front() << ' ';
        q.pop();
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 B: 用筛法求质数

题目描述
用筛选法求出100以内的全部质数,并按每行五个数显示。
输入

输出
100以内的全部质数
提示
如果用c++的cout输出,在本题中可以使用setw(5)
setw(n)是在输出时分配了n个字符的输出宽度
如果用C的printf输出,可以用%5d
思路
素数筛为数论基础内容,以下的为线性方式

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;
bool st[N];
int prime[N], cnt;

//筛出n以内的质数,存于prime里,cnt表示个数
void get_prime(int n){
    for (int i = 2; i <= n; i ++ ){
        //如果未曾标记过就一定是素数
        if (!st[i]) prime[cnt ++ ] = i;
        //循环条件限制的prime[j] * i不超过数组的范围
        for (int j = 0; prime[j] <= n / i; j ++ ){
            //目前的i与已经筛出来的素数相乘得到的数不是素数,标记
            st[prime[j] * i] = true;
            //不用进行j<cnt的限制,分类讨论
            //若i为素数,则已经筛出的最后一个prime会是自己,自己%自己=0
            //若i为非素数,则一定会被某个素数整除,且该素数小于自己
            if (i % prime[j] == 0) break;
        }
    }
}

void solve()
{
    int n;
    n = 100;
    get_prime(n);
    for (int i = 0; i < cnt; ){
        for (int j = 0; j < 5; j ++ ){
            if (i >= cnt) break;
            cout << setw(5) << prime[i ++ ];
        }
        cout << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 C: 笨小猴

题目描述
笨小猴的词汇量很小,所以每次做英语选择题的时候都很头痛。经实验证明,用这种方法去选择选项的时候选对的几率非常大!
这种方法的具体描述如下:假设maxn是单词中出现次数最多的字母的出现次数,minn是单词中出现次数最少的字母的出现次数,如果maxn-minn是一个质数,那么笨小猴就认为这是一个Lucky Word,这样的单词很可能就是正确答案。
输入
只有一行,是一个单词,其中只可能出现小写字母,且长度小于100。
输出
共两行,第一行是一个字符串,假如输入的单词是Lucky Word,那么输出“Lucky Word”,否则输出“No Answer”;
第二行是一个整数,如果输入单词是Lucky Word,输出maxn-minn的值,否则输出0。
样例输入

error

样例输出

Lucky Word
2

提示
【输入输出样例解释】
单词error中出现最多的字母r出现了3次,出现次数最少的字母出现1次,3-1=2,2是质数。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int p[26];

bool sushu(int n){
    if (n < 2) return false;
    if (n == 2) return true;
    for (int i = 2; i <= n / i; i ++ ){
        if (n % i == 0) return false;
    }
    return true;
}

void solve()
{
    string s;
    cin >> s;
    int maxn = 0, minn = N;
    for (int i = 0; i < s.size(); i ++ ){
        s[i] = tolower(s[i]);
        p[s[i] - 'a'] ++;
    }
    for (int i = 0; i < 26; i ++ ){
        maxn = max(maxn, p[i]);
        if(p[i]) minn = min(minn, p[i]);
    }
    if (sushu(maxn - minn)){
        cout << "Lucky Word" << endl << maxn - minn << endl;
    }else{
        cout << "No Answer" << endl << 0 << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 D: 计算组合数

题目描述
计算组合数C(m, n)的值(n <= m <= 10)
输入
输入包含两个非负整数,用空格分隔
输出
输出仅一行,一个数即C(m,n)
样例输入

4 1

样例输出

4

提示
C(m,n) = m!/((m-n)! * n!)
思路
以下方法适用于n,m<= 2000的情况,再多用卢卡斯定理

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int c[11][11];

void solve()
{
    //在a里面选b个等于在a-1中选b个加上a - 1里选b - 1个
    //在a-1里选b-1个等于确定选a里第a个的a里面选b个的方案,a-1中选b个则为确定不选第a个
    for (int i = 0; i <= 10; i ++ ){
        for (int j = 0; j <= i; j ++ ){
            if (!j) c[i][j] = 1;
            else c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
        }
    }
    int m, n;
    cin >> m >> n;
    cout << c[m][n] << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 E: 整理药名

题目描述
医生在书写药品名的时候经常不注意大小写,格式比较混乱。现要求你写一个程序将医生书写混乱的药品名整理成统一规范的格式,即药品名的第一个字符如果是字母要大写,其他字母小写。如将ASPIRIN、aspirin整理成Aspirin。
输入
第一行一个数字n,表示有n个药品名要整理,n不超过100。
接下来n行,每行一个单词,长度不超过20,表示医生手书的药品名。药品名由字母、数字和-组成。
输出
n行,每行一个单词,对应输入的药品名的规范写法。
样例输入

4
AspiRin
cisapride
2-PENICILLIN
Cefradine-6

样例输出

Aspirin
Cisapride
2-penicillin
Cefradine-6
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;

void solve()
{
    int n;
    cin >> n;
    while (n -- ){
        string s;
        cin >> s;
        s[0] = toupper(s[0]);
        for (int i = 1; i < s.size(); i ++ ){
            s[i] = tolower(s[i]);
        }
        cout << s << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 F: 矩阵转置

题目描述
输入一个n行m列的矩阵A,输出它的转置AT。
输入
第一行包含两个整数n和m,表示矩阵A的行数和列数(1≤n≤100,1≤m≤100)。
接下来n行,每行m个整数,表示矩阵A的元素。相邻两个整数之间用单个空格隔开,每个元素均在1~1000之间。
输出
m行,每行n个整数,为矩阵A的转置。相邻两个整数之间用单个空格隔开。
样例输入

3 3
1 2 3
4 5 6
7 8 9

样例输出

1 4 7
2 5 8
3 6 9
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;

void solve()
{
    int n, m;
    cin >> n >> m;
    int a[n][m];
    for (int i = 0; i < n; i ++ ){
        for (int j = 0; j < m; j ++ ){
            cin >> a[i][j];
        }
    }

    for (int j = 0; j < m; j ++ ){
        for (int i = 0; i < n; i ++ ){
            cout << a[i][j] << ' ';
        }
        cout << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 G: 素数判定优化

题目描述
判定n是否为一个素数,且n的最大值为1e18。显然如果用一般方法,则耗时高,因此需要一定的优化。
输入
输入数据有多组,每组数据占一行。
当输入0时结束。
0<=n<=1e18。
输出
如果输入的n为素数,则输出"OK",否则请输出“Sorry”,每组输出占一行。(实际输出均不带引号)
样例输入
5
6
0
样例输出
OK
Sorry
提示
规律:
除2和3以外的所有素数,都可以写成6k-1或6k+1(k为整数),即当一个数在6的倍数的两侧时,它可能是素数,但当其不满足条件时,它一定不是素数。
思路
6k+0一定被6整除,6k+2一定被2整除,6k+3一定被3整除,6k+4一定被2整除,所以素数一定是6k+1或者+5

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;

bool sushu(int n){
    if (n < 2) return false;
    if (n == 2 || n == 3) return true;
    if (n % 6 != 1 && n % 6 != 5) return false;
    //素数比在6的倍数左右,其他不用判断
    for (int i = 5; i <= n / i; i += 6){
        if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

void solve()
{
    int n;
    while(cin >> n , n){
        if (sushu(n)) cout << "OK" << endl;
        else cout << "Sorry" << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 H: 水仙花数

题目描述
春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,他是这样定义的:
“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=13+53+3^3。
现在要求输出所有在m和n范围内的水仙花数。
输入
输入数据有多组,每组占一行,包括两个整数m和n(100<=m<=n<=999)。
输出
对于每个测试实例,要求输出所有在给定范围内的水仙花数,就是说,输出的水仙花数必须大于等于m,并且小于等于n,如果有多个,则要求从小到大排列在一行内输出,之间用一个空格隔开;
如果给定的范围内不存在水仙花数,则输出no;
每个测试实例的输出占一行。
样例输入

100 120

样例输出

no
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e6 + 10;

bool check(int n){
    int sum = 0;
    int nn = n;
    while(n){
        int t = n % 10;
        n /= 10;
        sum += pow(t, 3);
    }
    if (nn == sum) return true;
    else return false;
}

void solve()
{
    int n, m;
    while(cin >> n >> m){
        bool flag = false;
        for (int i = n; i <= m; i ++ ){
            if (check(i)){
                cout << i << ' ';
                flag = true;
            }
        }
        if (flag) cout << endl;
        else cout << "no" << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 I: [蓝桥杯2022初赛] 选数异或

题目描述
给定一个长度为 n 的数列A1,A2,… , An 和一个非负整数 x。
给定 m 次查询, 每次询问能否从某个区间 [l, r] 中选择两个数使得他们的异或等于 x。
输入
输入第一行包含三个整数n,m,x。
第二行包含n个整数A1,A2,…,An。
接下来m行,每行两个整数l,r表示询问区间[l, r]。
20%的测试数据:1≤n,m≤100;
40%的测试数据:1≤n,m≤1000;
100%的测试数据:1≤n,m≤100000,0≤x,Ai<2^20,1≤l≤r≤n;
输出
对于每个询问, 如果该区间内存在两个数的异或为 x 则输出yes, 否则输出no。
样例输入

4 4 1
1 2 3 4
1 4
1 2
2 3
3 3

样例输出

yes
no
yes
no

思路
假设我们有一个函数f(b)为b左边最靠右的与b异或等于x的位置。函数g相当于f的前缀最大值,这样我们就只需要知道右端点之前的最靠右的能配对的值f? 是都大于l就可以了

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;
const int N = 1e5 + 10, M = (1 << 20) + 10;
int f[M], g[N];

void solve()
{
    int n, m, x;
    cin >> n >> m >> x;
    for (int i = 1; i <= n; i ++ ){
        int b;
        cin >> b;
        //在指定区间内找a^b=x则相当于在b左边找一个数等于b^x
        g[i] = max(g[i - 1], f[b ^ x]);
        //f[b]记录为最靠右出现b的位置
        //g[i]为该位置(i)以及之前的位置能配对的最靠右的值
        f[b] = i;
    }
    while(m -- ){
        int l, r;
        cin >> l >> r;
        if (g[r] >= l) cout << "yes" << endl;
        else cout << "no" << endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 J: [蓝桥杯2022初赛] 纸张尺寸

题目描述
在ISO 国际标准中定义了A0 纸张的大小为1189mm × 841mm。
将A0 纸沿长边对折后为A1 纸,大小为841mm × 594mm。
在对折的过程中长度直接取下整(实际裁剪时可能有损耗)。
将A1 纸沿长边对折后为A2 纸,依此类推。
输入纸张的名称,请输出纸张的大小。
输入
输入一行包含一个字符串表示纸张的名称。
该名称一定是A0、A1、A2、A3、A4、A5、A6、A7、A8、A9 之一。
输出
输出两行,每行包含一个整数,依次表示长边和短边的长度。
样例输入

样例1:
A0

样例2:
A1

样例输出

样例1:
1189
841

样例2:
841
594

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
typedef pair<int, int> PII;

void solve()
{
    string s;
    cin >> s;
    int k = s[1] - '0';
    int a = 1189, b = 841;
    while(k -- ){
        if (a < b) swap(a, b);
        a /= 2;
    }
    if (a < b) swap(a, b);
    cout << a << endl << b << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 K: 添柴少年

题目描述
福葛又在暴揍纳兰珈!
因为小飞机连两个数的最小公倍数都不会求。
你能帮一帮他吗?
输入
两个正整数,每个整数在long long定义的C语言整数类型范围内。
输出
两个数的最小公倍数
样例输入

7 9

样例输出

63

提示
C语言中long long类型的整数输入输出对应的格式化字符串为“%lld”

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long

void solve()
{
    int a, b;
    cin >> a >> b;
    cout << a * b / __gcd(a, b) << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 L: 你的就是我的,我的还是我的

题目描述
小F对小M说:
你的就是我的,我的还是我的。
初始时小M有 A AA 块饼干,小F有 B BB 块饼干。
小F会进行下面操作共 K KK 次:
如果小M还有饼干,就吃掉一块儿她的饼干
否则,如果小F还有饼干,就吃掉一块儿自己的饼干
如果两人都没有饼干了,就结束操作
输入
输入描述
输入包括一行空格隔开的三个正整数 A B K
0 ≤ A ≤ 1e12
0 ≤ B ≤ 1e12
0 ≤ K ≤ 1e12
输出
输出一行空格隔开的两个字符串,分别代表小M和小F剩下的饼干数。
样例输入

2 3 3

样例输出

0 2
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long

void solve()
{
    int a, b, k;
    cin >> a >> b >> k;
    a -= k;
    if (a >= 0){
        cout << a << ' ' << b << endl;
    }else{
        b += a;
        a = 0;
        if (b >= 0){
            cout << a << ' ' << b << endl;
        }else{
            cout << "0 0" << endl; 
        }
    }
    
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 M: 下一个素数

题目描述
小T说:请找到不小于T的最小的素数
素数是除了1和自身外不能被其他整数整除的大于1的正整数
输入
输入包括一行一个正整数T
2<=T<=10^5
输出
输出一行一个正整数,代表不小于T的最小素数
样例输入

20

样例输出

23

思路
该方法比较简单,如果想要更快,可以先筛出100000以内的素数,之后用二分查找

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long

bool sushu(int n){
    if (n == 2) return true;
    for (int i = 2; i <= n / i; i ++ ){
        if (n % i == 0) return false;
    }
    return true;
}

void solve()
{
    int n;
    cin >> n;
    while(!sushu(n)) n ++;
    cout << n << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 N: 三角形牧场

题目描述
和所有人一样,奶牛喜欢变化。它们正在设想新造型的牧场。奶牛建筑师John想建造围有漂亮白色栅栏的三角形牧场。
他拥有
块木板,每块的长度
都是整数。
他想要选三块木板,使得它们的长度能够构成一个三角形,请问有多少种选择方法呢?
输入
第一行,一个整数,代表 n (<=2*10^3)
第二行,n个整数,代表Ai (<=10^3)
输出
输出一个整数,代表方案数
样例输入

5
1 2 3 4 3

样例输出

5

提示
样例解释:共五种方案:(1,3,3),(2,3,3),(2,3,4),(2,3,4),(3,3,4)
思路
将边长排序,枚举三角形的两条边,推算出能组成三角形的第三边的最长最短值,进行二分,之间的值都能组成三角形。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
const int N = 2003;
int a[N];

void solve()
{
    int n;
    cin >> n;
    int sum = 0;
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    sort(a, a + n);
    for (int i = 0; i < n - 2; i ++ ){
        for (int j = i + 1; j < n - 1; j ++ ){
            int ma = a[i] + a[j] - 1;
            int mi = max(a[i], a[j]) - min(a[i], a[j]) + 1;
            int l = j + 1, r = n - 1, mid;
            int ll, rr;
            //第一个大于等于mi的位置
            while(l < r){
                mid = l + r >> 1;
                if(a[mid] >= mi) r = mid;
                else l = mid + 1;
            }
            ll = l;
            l = j + 1, r = n - 1;
            while(l < r){
                mid = l + r + 1 >> 1;
                if (a[mid] <= ma) l = mid;
                else r = mid - 1;
            }
            rr = l;
            // cout << ll << ' ' << rr << endl;
            if (a[ll] >= mi && a[rr] <= ma) sum += rr - ll + 1;
        }
    } 
    cout << sum << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 O: 异或和

在这里插入图片描述
样例输入

3
1 2 3

样例输出

6

提示
样例2:
输入:

10
3 1 4 1 5 9 2 6 5 3

输出:

237

样例3:
输入:

10
3 14 159 2653 58979 323846 2643383 27950288 419716939 9375105820

输出:

103715602

思路
就把每个数看成二进制数,cnt表示每个二进制位上的1的个数. 1与0异或则为1,1的个数乘上0的个数乘上权重就为该位贡献的值,每个位加起来就是答案。
需要主要的一点就是2的60次方超long long了,需要得用快速幂取余算。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long
const int N = 110, mod = 1e9 + 7;
int res;
int cnt[N];

LL qpow(int a, int b, int p){
    LL res = 1 % p;
    while(b){
        if(b & 1) res = res * a % p;
        a = (LL)a * a % p;
        b >>= 1;
    }
    return res;
}

void solve()
{
    int n;
    cin >> n;
    int m = 1;
    for (int i = 0; i < n; i ++ ){
        int a, len = 0;
        cin >> a;
        while(a){
            len ++;
            if(a & 1) cnt[len] ++;
            a >>= 1;
        }        
        m = max(m, len);
    }
    for (int i = 1; i <= m; i ++ ){
        //1和0组合异或为1,1的个数×0的个数为组合数
        res += (qpow(2, i - 1, mod) * cnt[i]) % mod * (n - cnt[i]) % mod;
        res %= mod;
    }
    cout << res << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}

问题 Q: 打怪兽version-2

题目描述
有一只怪兽的血量为H
你需要在N回合之内杀死它
第i个回合你可以对其造成ai点伤害
问是否可以杀死怪兽(其血量小于等于0即为死亡)
可以输出Yes
否则输出No
输入
H N
a1,a2…an
1 <= H <= 1e9
1 <= N <= 1e5
1 <= ai <=1e4
输出
问是否可以杀死怪兽(其血量小于等于0即为死亡)
可以输出Yes
否则输出No
样例输入

10 3
4 5 6

样例输出

Yes
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int long long

void solve()
{
    int h, n;
    cin >> h >> n;
    int sum = 0, a;
    while(n -- ){
        cin >> a;
        sum += a;
    }
    if (sum >= h) cout << "Yes" << endl;
    else cout << "No" << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t -- ) solve();
    system("pause");
    return 0;
}
文章来源:https://blog.csdn.net/m0_65620244/article/details/135745269
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。