【第十二届蓝桥杯】【第二场】【C++B组】【学习笔记】蓝桥杯每日一练day2

汪汪汪,不如第一场麻 😄 ,day2

A、求余(5分)

在这里插入图片描述

#include<iostream>
using namespace std;
int main()
{
	cout<<2021%20<<endl;
	return 0;
} 
// 1

B、双阶乘(5分)

在这里插入图片描述

这里硬算,必爆,所以我们每次乘都要取余

1 x 3 x 5 x 7 ... x 2021 % MOD // 由乘法和取模的性质,我们可以边乘边取模
#include<iostream>
using namespace std;
int main()
{
	int res = 1;
	for(int i = 1 ; i <= 2021 ; i += 2)
			res = res * i % 100000;
	cout<<res<<endl;
	return 0;
} 
// 59375

C、格点(10分)

在这里插入图片描述

👴没仔细看题嗷,x和y从0开始枚举了,考试这样必寄

#include<iostream>
using namespace std;
int main()
{
	int res = 0;
	for(int x = 1 ; x <= 2021 ; x++)
		for(int y = 1 ; y  <= 2021  ; y++)
			if(x * y <= 2021)
				res++;
	cout<<res<<endl;
	return 0;
} 
// 15698

D、整数分解(10分)

在这里插入图片描述

非常简单只要

#include<iostream>
using namespace std;
int main()
{
    long long res = 0;
    for(int i = 1 ; i <= 2021 ; i++)
        for(int j = 1 ; j <= 2021 - i ; j++)
            for(int k = 1 ; k <= 2021 - i - j ; k++)
                for(int l = 1 ; l <= 2021 - i - j - k ; l++)
                    for(int m = 1 ; m <= 2021 - i - j - k - l ; m++)
                        if(i + j + k + l + m == 2021)
                            res++;
    cout<<res<<endl;
    return 0;
} 

哈哈哈,开玩笑的,我跑了3分钟都没跑出来

这题用隔板法

所以这题就转化为求 C 2020 4 C_{2020}^{4} C20204

#include<iostream>
using namespace std;
int main()
{
	long long res = 1;
	for(int i = 2020 ,j = 1 ; j <= 4 ; i--,j++)
		res = res * i / j;
	cout<<res<<endl;
	
	return 0;
} 
// 691677274345

E、城邦(15分)

在这里插入图片描述

最小生成树,y总写的Kruskal,不说了,今天复习图论了,早该忘忘了

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

using namespace std;

const int N = 2030, M = N * N / 2;

int n = 2021, m;
int p[N];
struct Edge
{
    int a, b, c;
    bool operator< (const Edge& t) const
    {
        return c < t.c;
    }
}e[M];

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

int get(int x, int y)
{
    int res = 0;
    while (x || y)
    {
        int a = x % 10, b = y % 10;
        if (a != b) res += a + b;
        x /= 10, y /= 10;
    }

    return res;
}

int main()
{
    for (int i = 1; i <= n; i ++ ) p[i] = i;
    for (int i = 1; i <= n; i ++ )
        for (int j = i + 1; j <= n; j ++ )
            e[m ++ ] = {i, j, get(i, j)};
    sort(e, e + m);

    int res = 0;
    for (int i = 0; i < m; i ++ )
    {
        int a = e[i].a, b = e[i].b, c = e[i].c;
        if (find(a) != find(b))
        {
            res += c;
            p[find(a)] = find(b);
        }
    }

     cout<<res<<endl;

    return 0;
}
// 4046

F、特殊年份(15分)

今年是 2021 年,2021 这个数字非常特殊,它的千位和十位相等,个位比百位大 1,我们称满足这样条件的年份为特殊年份。

输入 5 个年份,请计算这里面有多少个特殊年份。

输入格式

输入 5 行,每行一个 4 位十进制数(数值范围为 1000 至 9999),表示一个年份。

输出格式

输出一个整数,表示输入的 5 个年份中有多少个特殊年份。

输入样例:

2019
2021
1920
2120
9899

输出样例:

2

样例解释

2021 和 9899 是特殊年份,其它不是特殊年份。

嗯造就完事了,语法题,y总直接用字符串来读然后来比较,那样做更简单
#include<iostream>
using namespace std;
int main()
{
    int m = 5;
    int res = 0;
    while(m--)
    {
        int year;
        cin>>year;
        int a = year / 1000,b = year % 1000 / 100,
        c = year % 100 / 10,d = year % 10;
        if(a == c && d - 1 == b)
            res ++;
    }
    cout<<res<<endl;
    return 0;
}

G、小平方(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。

输出格式

输出一个整数,表示满足条件的数的数量。

数据范围

1≤n≤1000

输入样例:

5

输出样例:

2
把 < 看成 <= 加油(ง •_•)ง
#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    int res = 0;
    for(int i = 1 ;i < n ; i++)
        if(i * i % n * 2  <  n )	// 防止取整问题
            res ++;
    cout<<res<<endl;
    return 0;
}

H、完全平方数(20分)

一个整数 a 是一个完全平方数,是指它是某一个整数的平方,即存在一个整数 b,使得 a = b 2 a = b^2 a=b2

给定一个正整数 n,请找到最小的正整数 x,使得它们的乘积是一个完全平方数。

输入格式

输入一行包含一个正整数 n。

输出格式

输出找到的最小的正整数 x。

数据范围

对于 30% 的评测用例,1≤n≤1000,答案不超过 1000。
对于 60% 的评测用例,1≤n≤ 1 0 8 10^8 108,答案不超过 1 0 8 10^8 108
对于所有评测用例,1≤n≤ 1 0 12 10^{12} 1012,答案不超过 1 0 12 10^{12} 1012

输入样例1:

12

输出样例1:

3

输入样例2:

15

输出样例2:

15
分解质因数,嗨呀,数论也忘了不少捏🤗

如果 n ∗ x = m 2 n * x = m ^ 2 nx=m2 ,就可以得出结论,m的任何一个质因子的次数都是偶数,只有是偶数,质因子才能分成2份,所以这题就是,给我们一个n,让我们求n至少乘上多少,使得n里面,每个质因子的次数变成偶数

#include<iostream>
using namespace std;
typedef long long LL;
int main()
{
    LL n;
    cin>>n;
    LL res = 1;
    for(LL i = 2 ; i * i <= n ; i++)
        if(n % i == 0)
        {
            int s = 0;
            while(n % i == 0) s++,n /= i;
            if(s % 2) res *= i;
        }
    if(n > 1) res *= n;
    cout<<res<<endl;
    return 0;
}

I、负载均衡(25分)

有 n台计算机,第 i 台计算机的运算能力为 v i v_i vi

有一系列的任务被指派到各个计算机上,第 i 个任务在 a i a_i ai 时刻分配,指定计算机编号为 b i b_i bi,耗时为 c i c_i ci 且算力消耗为 d i d_i di

如果此任务成功分配,将立刻开始运行,期间持续占用 b i b_i bi 号计算机 d i d_i di 的算力,持续 c i c_i ci 秒。

对于每次任务分配,如果计算机剩余的运算能力不足则输出 −1,并取消这次分配,否则输出分配完这个任务后这台计算机的剩余运算能力。

输入格式

输入的第一行包含两个整数 n,m 分别表示计算机数目和要分配的任务数。

第二行包含 n 个整数 v1,v2,⋅⋅⋅ v n v_n vn,分别表示每个计算机的运算能力。

接下来 m 行每行 4 个整数 a i a_i ai, b i b_i bi, c i c_i ci, d i d_i di,意义如上所述。数据保证 a i a_i ai 严格递增,即 a i < a i + 1 a_i<a_{i+1} ai<ai+1

输出格式

输出 m 行,每行包含一个数,对应每次任务分配的结果。

数据范围

对于 20% 的评测用例,n,m≤200。
对于 40% 的评测用例,n,m≤2000。
对于所有评测用例,1≤n,m≤200000,1≤ a i a_i ai, c i c_i ci, d i d_i di, v i v_i vi 1 0 9 10^9 109,1≤ b i b_i bi≤n

输入样例:

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 个任务,剩余算力足够,且恰好用完。

模拟题,可以发现,每个计算机之间互相不会影响,我们可以用优先队列来维护每一个计算机
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 200010;
int n,m;
int s[N];
priority_queue<PII,vector<PII>,greater<PII>> q[N];

int main()
{
    cin>>n>>m;
    for(int i = 1 ; i <= n ; i++) cin>>s[i];
    while(m--)
    {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        while(q[b].size() && q[b].top().x <= a)
        {
            s[b] += q[b].top().y;
            q[b].pop();
        }
        if(s[b] < d) puts("-1");
        else
        {
            q[b].push({a + c,d});
            s[b] -= d;
            cout<<s[b]<<endl;
        }
    }
    return 0;
}

J、国际象棋(25分)

众所周知,“八皇后” 问题是求解在国际象棋棋盘上摆放 8 个皇后,使得两两之间互不攻击的方案数。

已经学习了很多算法的小蓝觉得 “八皇后” 问题太简单了,意犹未尽。作为一个国际象棋迷,他想研究在 N×M的棋盘上,摆放 K 个马,使得两两之间互不攻击有多少种摆放方案。

由于方案数可能很大,只需计算答案除以 1000000007 (即 1 0 9 10^9 109+7) 的余数。

如下图所示,国际象棋中的马摆放在棋盘的方格内,走 “日” 字,位于 (x,y)(x,y) 格的马(第 x 行第 y 列)可以攻击 (x+1,y+2)(x+1,y+2)、(x+1,y−2)(x+1,y−2)、(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)、(x−2,y+1)(x−2,y+1) 和 (x−2,y−1)(x−2,y−1) 共 8 个格子。

QQ截图20210512104039.png

输入格式

输入一行包含三个正整数 N,M,K 分别表示棋盘的行数、列数和马的个数。

输出格式

输出一个整数,表示摆放的方案数除以 1000000007 (即 1 0 9 10^9 109+7) 的余数。

数据范围

对于 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。

输入样例1:

1 2 1

输出样例1:

2

输入样例2:

4 4 3

输出样例2:

276

输入样例3:

3 20 12

输出样例3:

914051446

在这里插入图片描述

f[i][a][b][j] 表示:前 i 行 放了 j 匹马,第 i 行 b 是 , i - 1 行是 a

对于每一个位置,有没有马,我们用二进制数表示,0 表示没有马,1 表示有马

状态转移 f[i-1][c][a][j-count(b)] ---->f[i][a][b][j]

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N  = 110,M = 1 << 6,K = 21,MOD = 1e9 + 7;
int n,m,k;
int f[N][M][M][K];

int get_count(int x)
{
    int res = 0;
    while(x)
    {
        res++;
        x -= x & -x;
    }
    return res;
}
int main()
{
    cin >> n >> m >> k;
    f[0][0][0][0] = 1;
    for(int i = 1 ; i <= m ; i ++)
        for(int a = 0 ; a < 1 << n ; a ++)
            for(int b = 0 ; b < 1 << n ; b++)
            {
                if(b & (a << 2) || a & (b << 2)) continue; // 如果b行和a行的马相差2个位置
                for(int c = 0 ; c < 1 << n ; c++)
                {
                    if(c & (a << 2) || a & (c << 2)) continue; // 如果c行和a行的马相差2个位置
                    if(c & (b << 1) || b & (c << 1)) continue; // 如果c行和b行的马相差1个位置
                    int t = get_count(b);
                    for(int j = t ; j <= k ; j++)
                        f[i][a][b][j] = (f[i][a][b][j] + f[i-1][c][a][j-t]) % MOD;
                }
            }
    int res = 0;
    for(int a = 0 ; a < 1 << n ; a ++)
        for(int b = 0 ; b < 1 << n ; b ++)
            res = (res + f[m][a][b][k]) % MOD;
    cout<<res<<endl;
    return 0;
}

有点麻,但是和第一场相比,真的不是一个级别

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值