第十二届蓝桥杯C++B组省赛第二场

试题 A: 求余

本题总分:5 分

【问题描述】
在 C/C++/Java/Python 等语言中,使用 % 表示求余,请问 2021%20 的
值是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
ans:1

#include <iostream>
using namespace std;

int main()
{
    cout << 2021 % 20 ;
    return 0;
}

试题 B: 双阶乘

本题总分:5 分

【问题描述】
一个正整数的双阶乘,表示不超过这个正整数且与它有相同奇偶性的所有
正整数乘积。n 的双阶乘用 n!! 表示。
例如:
3!! = 3 × 1 = 3。
8!! = 8 × 6 × 4 × 2 = 384。
11!! = 11 × 9 × 7 × 5 × 3 × 1 = 10395。
请问,2021!! 的最后 5 位(这里指十进制位)是多少?
注意:2021!! = 2021 × 2019 × · · · × 5 × 3 × 1。
提示:建议使用计算机编程解决问题
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
ans:59375

代码A:

#include <iostream>
#include <algorithm>
using namespace std;

string mul(string A,int b)
{
    string res;
    reverse(A.begin(),A.end());
    int t=0;
    for(int i=0;i<A.size()||t;i++)
    {
        if(i<A.size()) t+=(A[i]-'0')*b;
        res.push_back('0'+t%10);
        t/=10;
    }
    reverse(res.begin(),res.end());
    return res;
}

int main()
{
    string res = "1";
    for(int i=1;i<=2021;i+=2)
        res = mul(res,i);  // 杀鸡用牛刀

    for(int i=res.size()-5;i<res.size();i++) cout<<res[i];
    
    return 0;
}

代码B:

#include <iostream>
using namespace std;

const int MOD = 100000;

int main()
{
    int ans=1;
    for(int i=1;i<=2021;i+=2)
        ans=(ans*i)%MOD;
    cout<<ans;
    return 0;
}

试题 C: 格点

本题总分:10 分

【问题描述】
如果一个点 (x, y) 的两维坐标都是整数,即 x ∈ Z 且 y ∈ Z,则称这个点为
一个格点。
如果一个点 (x, y) 的两维坐标都是正数,即 x > 0 且 y > 0,则称这个点在
第一象限。
请问在第一象限的格点中,有多少个点 (x, y) 的两维坐标乘积不超过 2021, 即 x · y ≤ 2021。
提示:建议使用计算机编程解决问题。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
ans:15698

#include <iostream>
#include <algorithm>
using namespace std;

int ans;

int main()
{
    int n=2021;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i*j<=n) ans++;
    cout<<ans;
    return 0;
}

试题 D: 整数分解

本题总分:10 分

【问题描述】
将 3 分解成两个正整数的和,有两种分解方法,分别是 3 = 1 + 2 和
3 = 2 + 1。注意顺序不同算不同的方法。
将 5 分解成三个正整数的和,有 6 种分解方法,它们是 1+1+3 = 1+2+2 =
1 + 3 + 1 = 2 + 1 + 2 = 2 + 2 + 1 = 3 + 1 + 1。
请问,将 2021 分解成五个正整数的和,有多少种分解方法?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
ans:691677274345

代码A:

#include <iostream>
using namespace std;

int n,path[8];
int ans;

void dfs(int k)
{
    int sum=0;
    for(int i=0;i<k;i++)
        sum += path[i];
    if(sum>n) return ;

    if(k==5)
    {
        if(sum==n) ans++;
        return ;
    }

    for(int i=1;i<=n;i++)
    {
        path[k]=i;
        dfs(k+1);
    }
}

int main()
{
    cin >> n;
    dfs(0);
    cout<<ans;
    return 0;
}

代码B:

#include<iostream>
using namespace std;

long long ans;

int main()
{
    int n = 2021;
    for(int i = 1;i < n; i++) {
        for(int j = 1;j < n; j++) {
            for(int k = 1;k < n; k++) {
                    int m = n - i - j - k; // 两个数和为m的方案数为:m-1
                    if(m <= 1) break;
                    ans += m - 1;
            }
        }
    }
    cout<<ans;
    return 0;
}

代码C:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;

LL C(int a,int b)
{
    LL res=1;
    for(int i=a,j=1;j<=b;i--,j++)
        res=res*i/j;
    return res;
}

int main()
{
    cout<<C(2020,4); // 挡板法
    return 0;
}

试题 E: 城邦

本题总分:15 分

【问题描述】
小蓝国是一个水上王国,有 2021 个城邦,依次编号 1 到 2021。在任意两
个城邦之间,都有一座桥直接连接。
为了庆祝小蓝国的传统节日,小蓝国政府准备将一部分桥装饰起来。
对于编号为 a 和 b 的两个城邦,它们之间的桥如果要装饰起来,需要的费
用如下计算:找到 a 和 b 在十进制下所有不同的数位,将数位上的数字求和。
例如,编号为 2021 和 922 两个城邦之间,千位、百位和个位都不同,将这
些数位上的数字加起来是 (2 + 0 + 1) + (0 + 9 + 2) = 14。注意 922 没有千位,千
位看成 0。
为了节约开支,小蓝国政府准备只装饰 2020 座桥,并且要保证从任意一个
城邦到任意另一个城邦之间可以完全只通过装饰的桥到达。
请问,小蓝国政府至少要花多少费用才能完成装饰。
提示:建议使用计算机编程解决问题。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
ans:4046

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5000010;
int n,m;
int p[N];

struct Edge
{
    int a,b,w;
    bool operator< (Edge &t) const
    {
        return w<t.w;
    }
}edge[N];

int find(int x)
{
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edge,edge+m);
    for(int i=1;i<=n;i++) p[i]=i;
    int res=0;
    int cnt=0;
    for(int i=0;i<m;i++)
    {
        int a=edge[i].a,b=edge[i].b,w=edge[i].w;
        a=find(a),b=find(b);
        if(a!=b)
        {
            res+=w;
            cnt++;
            p[a]=b;
        }
        if(cnt==n-1) 
            break;
    }
    return res;

}

int calc(int x,int y)
{
   int res=0;
   int a1=x%10,b1=x/10%10,c1=x/10/10%10,d1=x/1000;  
   int a2=y%10,b2=y/10%10,c2=y/10/10%10,d2=y/1000;
   if(a1!=a2) res += a1+a2;
   if(b1!=b2) res += b1+b2;
   if(c1!=c2) res += c1+c2;
   if(d1!=d2) res += d1+d2;
   return res;
}

int main()
{
    n = 2021;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            edge[m++]={i,j,calc(i,j)};
   cout<<kruskal();
    return 0;
}

试题 F: 特殊年份

时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分

【问题描述】
今年是 2021 年,2021 这个数字非常特殊,它的千位和十位相等,个位比
百位大 1,我们称满足这样条件的年份为特殊年份。
输入 5 个年份,请计算这里面有多少个特殊年份。
【输入格式】
输入 5 行,每行一个 4 位十进制数(数值范围为 1000 至 9999),表示一个
年份。
【输出格式】
输出一个整数,表示输入的 5 个年份中有多少个特殊年份。
【样例输入】
2019
2021
1920
2120
9899
【样例输出】
2
【样例说明】
2021 和 9899 是特殊年份,其它不是特殊年份。

#include <iostream>
using namespace std;

bool check(int x)
{
    int a=x/1000;
    int b=x/100%10;
    int c=x/10%10;
    int d=x%10;
    return a==c && d==b+1;
}

int main()
{
    int ans=0;
    for(int i=0;i<5;i++)
    {
        int x;
        cin >> x;
        if(check(x)) ans++;
    }
    cout<<ans;
    return 0;
}

试题 G: 小平方

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分

【问题描述】
小蓝发现,对于一个正整数 n 和一个小于 n 的正整数 v,将 v 平方后对 n
取余可能小于 n 的一半,也可能大于等于 n 的一半。
请问,在 1 到 n − 1 中,有多少个数平方后除以 n 的余数小于 n 的一半。
例如,当 n = 4 时,1, 2, 3 的平方除以 4 的余数都小于 4 的一半。
又如,当 n = 5 时,1, 4 的平方除以 5 的余数都是 1,小于 5 的一半。而
2, 3 的平方除以 5 的余数都是 4,大于等于 5 的一半。
【输入格式】
输入一行包含一个整数 n。
【输出格式】
输出一个整数,表示满足条件的数的数量。
【样例输入】
5
【样例输出】
2
【评测用例规模与约定】
对于所有评测用例,1 ≤ n ≤ 10000。

#include <iostream>
using namespace std;

int n;
int ans;

bool check(int x)
{
    return ((x*x)%n)*2 < n;
}


int main()
{
    cin >> n;
    for(int i=1;i<=n-1;i++)
        ans += check(i);
    cout<<ans;
    return 0;
}

试题 H: 完全平方数

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分

【问题描述】
一个整数 a 是一个完全平方数,是指它是某一个整数的平方,即存在一个
整数 b,使得 a = b^2。
给定一个正整数 n,请找到最小的正整数 x,使得它们的乘积是一个完全平
方数。
【输入格式】
输入一行包含一个正整数 n。
【输出格式】
输出找到的最小的正整数 x。
【样例输入 1】
12
【样例输出 1
3
【样例输入 2】
15
【样例输出 2】
15
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 1000,答案不超过 1000。
对于 60% 的评测用例,1 ≤ n ≤ 10^8,答案不超过 10^8。
对于所有评测用例,1 ≤ n ≤ 10^12,答案不超过 10^12。
代码A:

#include <iostream>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
int x;
int ans;
unordered_map<LL,bool> h;

int main()
{
    for(LL i=1;i<=500000;i++) h[i*i]=true;
    
    cin >> x;
    for(LL y=1;;y++)
        if(h[x*y])
        {
            cout<<y;
            break;
        }
    return 0;
}

代码B:

#include <iostream>
using namespace std;

typedef long long LL;
LL n;

int main()
{
    cin >> n;
    LL res=1;
    for(LL i=2;i*i<=n;i++)
        if(n%i==0)
        {
            int k=0;
            while(n%i==0) k++,n/=i;
            if(k%2==1) res*=i;  // 需要将n的所有质因子的次数变成偶数
        }
    if(n>1) res*=n;
    cout<<res;
    return 0;
}

试题 I: 负载均衡

时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分

【问题描述】
有 n 台计算机,第 i 台计算机的运算能力为 vi。
有一系列的任务被指派到各个计算机上,第 i 个任务在 ai 时刻分配,指定
计算机编号为 bi ,耗时为 ci 且算力消耗为 di 。如果此任务成功分配,将立刻
开始运行,期间持续占用 bi 号计算机 di 的算力,持续 ci 秒。
对于每次任务分配,如果计算机剩余的运算能力不足则输出 −1,并取消这
次分配,否则输出分配完这个任务后这台计算机的剩余运算能力。
【输入格式】
输入的第一行包含两个整数 n, m,分别表示计算机数目和要分配的任务数。
第二行包含 n 个整数 v1, v2, · · · vn,分别表示每个计算机的运算能力。
接下来 m 行每行 4 个整数 ai, bi, ci, di,意义如上所述。数据保证 ai 严格递
增,即 ai < ai+1。
【输出格式】
输出 m 行,每行包含一个数,对应每次任务分配的结果。
【样例输入】
2 6
5 5
1 1 5 3
2 2 2 6
3 1 2 3
4 1 6 1
5 1 3 3
6 1 3 4
【样例输出】
2
-1
-1
1
-1
0
【样例说明】
时刻 1,第 1 个任务被分配到第 1 台计算机,耗时为 5 ,这个任务时刻 6
会结束,占用计算机 1 的算力 3。
时刻 2,第 2 个任务需要的算力不足,所以分配失败了。
时刻 3,第 1 个计算机仍然正在计算第 1 个任务,剩余算力不足 3,所以
失败。
时刻 4,第 1 个计算机仍然正在计算第 1 个任务,但剩余算力足够,分配
后剩余算力 1。
时刻 5,第 1 个计算机仍然正在计算第 1, 4 个任务,剩余算力不足 4,失
败。
时刻 6,第 1 个计算机仍然正在计算第 4 个任务,剩余算力足够,且恰好
用完。
【评测用例规模与约定】
对于 20% 的评测用例,n, m ≤ 200。
对于 40% 的评测用例,n, m ≤ 2000。
对于所有评测用例,1 ≤ n, m ≤ 200000,1 ≤ ai, ci, di, vi ≤ 10^9,1 ≤ bi ≤ n。


试题 J: 国际象棋

时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分

【问题描述】
众所周知,“八皇后” 问题是求解在国际象棋棋盘上摆放 8 个皇后,使得两
两之间互不攻击的方案数。已经学习了很多算法的小蓝觉得 “八皇后” 问题太简
单了,意犹未尽。作为一个国际象棋迷,他想研究在 N × M 的棋盘上,摆放 K
个马,使得两两之间互不攻击有多少种摆放方案。由于方案数可能很大,只需
计算答案除以 1000000007 (即 109 + 7) 的余数。
如下图所示,国际象棋中的马摆放在棋盘的方格内,走 “日” 字,位于 (x, y)
格的马(第 x 行第 y 列)可以攻击 (x + 1, y + 2)、(x + 1, y − 2)、(x − 1, y + 2)、 (x − 1, y − 2)、(x + 2, y + 1)、(x + 2, y − 1)、(x − 2, y + 1) 和 (x − 2, y − 1) 共 8 个
格子。
在这里插入图片描述
【输入格式】
输入一行包含三个正整数 N, M, K,分别表示棋盘的行数、列数和马的个
数。
【输出格式】
输出一个整数,表示摆放的方案数除以 1000000007 (即 10^9 + 7) 的余数。
【样例输入】
1 2 1
【样例输出】
2
【样例输入】
4 4 3
【样例输出
276
【样例输入】
3 20 12
【样例输出】
914051446
【评测用例规模与约定】
对于 5% 的评测用例,K = 1;
对于另外 10% 的评测用例,K = 2;
对于另外 10% 的评测用例,N = 1;
对于另外 20% 的评测用例,N, M ≤ 6,K ≤ 5;
对于另外 25% 的评测用例,N ≤ 3,M ≤ 20,K ≤ 12;
对于所有评测用例,1 ≤ N ≤ 6,1 ≤ M ≤ 100,1 ≤ K ≤ 20。

暴力过45%的数据:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N = 1010, MOD = 1e9+7;
LL n,m,k;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int path[N];
int ans;

LL C(int a,int b)
{
    LL res=1;
    for(int i=a,j=1;j<=b;i--,j++)
        res=res*i/j%MOD;
    return res;
}

bool check(int a,int b,int c,int d) // 判断两个点是否有冲突
{
    if(a==c && b==d) return true;
    
    for(int i=0;i<8;i++)
    {
        int nx=a+dx[i],ny=b+dy[i];
        if(nx<0 ||nx>=n ||ny<0 ||ny>=m) continue;
        if(nx==c && ny==d) return true;
    }
    return false;
}

bool check2()
{
    for(int i=0;i<2;i++)
        for(int j=i+1;j<2;j++)
        {
            if(i==j) continue;
            int a=path[i]/m,b=path[i]%m;
            int c=path[j]/m,d=path[j]%m;
            if(check(a,b,c,d)) return true;
        }
    return false;
}

bool check3()
{
    for(int i=0;i<3;i++)
        for(int j=i+1;j<3;j++)
            for(int k=j+1;k<3;k++)
            {
                int a=path[i]/m,b=path[i]%m;
                int c=path[j]/m,d=path[j]%m;
                int e=path[k]/m,f=path[k]%m;
                if(check(a,b,c,d)||check(a,b,e,f)||check(c,d,e,f)) return true;
            }
    return false;
}

void dfs(int u,int start)
{
    if(u==k)
    {
        if(k==2 && !check2()) ans++;
        if(k==3 && !check3()) ans++;
        return ;
    }
    
    for(int i=start;i<n*m;i++)
    {
        path[u]=i;
        dfs(u+1,i+1);
    }
}

int main()
{
    cin >> n >> m >> k;
    if(k==1)
    {
        cout<<n*m%MOD;
    }
    else
    {
        if(n==1)
        {
            cout<<C(m,k);
        }
        else if(k<=5)
        {
            dfs(0,0);
            cout<<ans;
        }
        else
        {
            cout<<rand()%MOD;
        }
    }
    return 0;
}

只做了填空题,其余的日后补充。以上做的也不知道正确步。有错请指教 ^ _ ^

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值