2021.5.29 2022蓝桥杯练习赛4

2021.5.29 2022蓝桥杯练习赛4

闲话:
1、就难度而言,本次比较简单,应该可以轻松做完4到5题。考了贪心、模拟、矩阵快速幂、二进制的相关知识。
2、就体验而言,题面不好看,解释的较繁琐,差评。
3、本次做题十分快乐。

题目
1、试题 算法提高 交换Easy
在这里插入图片描述
解析:在读入数据后,可以通过swap(l,r)直接交换位置的值;当然也可以手写交换。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1005];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    while(m--){
        int l,r; cin>>l>>r;
        swap(a[l],a[r]);
    }
    for(int i=1;i<=n;i++) cout<<a[i]<<"\n";
}

----------------------------------------------------------------------------------------------------------------------------

2、试题 算法提高 矩阵乘方
在这里插入图片描述
解析:这是一道矩阵快速幂裸题,当然也可以模拟一路乘下去,应该也是可以的。直接上模板就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,mod;
const ll N=105;
struct mat{
	ll a[N][N];
};

mat multi(mat a,mat b,ll n){
	mat c;
	memset(c.a,0,sizeof(c.a));
	for(ll i=0;i<n;i++){
		for(ll j=0;j<n;j++){
			for(ll k=0;k<n;k++){
				c.a[i][j]+=a.a[i][k]*b.a[k][j];
				c.a[i][j]%=mod;
			}
		}
	}
	return c;
}

mat pow(mat c,ll n,ll k){
	mat res;
	for(int i=0;i<n;i++) res.a[i][i]=1;
	while(k){
		if(k&1) res=multi(res,c,n);
		c=multi(c,c,n);
		k>>=1;
	}
	return res;
}

int main(){
	scanf("%lld%lld",&n,&mod);
	mat c;
	for(ll i=0;i<2;i++){
		for(ll j=0;j<2;j++){
			scanf("%lld",&c.a[i][j]);
		}
	}
	mat ans=pow(c,2,n);
	for(ll i=0;i<2;i++){
		for(ll j=0;j<2;j++){
			printf("%lld ",ans.a[i][j]%mod);
		}
		printf("\n");
	}
}


----------------------------------------------------------------------------------------------------------------------------

3、试题 算法提高 打水问题
在这里插入图片描述
解析:很明显这是一道贪心题,为了使所有人的总等待时间最少。只需要我们在每次有空的龙头的时候,在当前还没有去打水的集合中,让打水需要时间最少的人去打水。这样总等待时间将最少。
----------------------------------------------------------------------------------------------------------------------------
写法一:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int ti[1005];
int a[1005];
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>ti[i];
    sort(ti,ti+n);  //打水顺序按大水需要时间从小到大排序
    for(int i=0;i<m;i++) a[i]=ti[i];  //最开始m个龙头都没有人用,所以最开始的m个人没有等待时间
    int sum=0;
    for(int i=m;i<n;i++){
        sum+=a[i%m];    //此时每个人都将分配到其对应的第i%m个龙头,“类似于将人按顺序使用龙头(可以自己理解一下)”
        a[i%m]+=ti[i];  //类似前缀和,即当下一次需要使用第i%m个龙头时,此时已经等待的时间
    }
    cout<<sum<<"\n";
}

----------------------------------------------------------------------------------------------------------------------------
写法二:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1010;

int n, m;
int t[maxn];
int sum[maxn];
int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) cin >> t[i];
	sort(t, t + n);
	for (int i = 0; i < n; i++) {
		sum[i % m] += t[i] * ((n - 1 - i) / m);
	}
	int ans = 0;
	for (int i = 0; i < m; i++) {
		ans += sum[i];
	}
	cout << ans << endl;
}

----------------------------------------------------------------------------------------------------------------------------
4、试题 算法训练 薪水计算
在这里插入图片描述
解析:无。直接根据题意分情况讨论就行了

#include<bits/stdc++.h>
using namespace std;
int main()
{
	double t,m,sum;
	cin>>t>>m;
	if(t<=40) sum=t*m;
	else if(t>40&&t<=50) sum=40*m+(t-40)*m*1.5;
	else sum=40*m+10*m*1.5+(t-50)*m*2;
	cout<<setiosflags(ios::fixed)<<setprecision(2)<<sum;
}

----------------------------------------------------------------------------------------------------------------------------
5、试题 算法训练 黑色星期五
在这里插入图片描述
解析:
1、写过类似日期的题目聚聚应该知道有一个根据年月日求星期几的公式----基姆拉尔森计算公式。知道这个公式这题就比较容易解决了。(这里不细说)
学习链接:C语言根据日期判断星期几(使用基姆拉尔森计算公式)
2、模拟,肯定是模拟,虽然这题我没用模拟,我直接上的公式 ,但模拟肯定是可以过的。模拟先从1998年1月1日开始,每次加上当前年份的天数到目标年份的前一年,然后将总天数%7得到某个值x,然后目标年份1月1日是星期几也就是星期四的后x天是星期几。
----------------------------------------------------------------------------------------------------------------------------
写法一:公式

#include <bits/stdc++.h>
using namespace std;
int year,month,day,sum=0,w;
int jisuan(int year,int month,int day){
	if(month==1||month==2){
		month+=12;
		year--;
	}
	return (day+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7+1;
}

int main(){
	cin>>year;
	day=13;
	for(int i=1;i<=12;i++){
		month=i;
		w=jisuan(year,month,day);
		if(w==5) sum++;
	}
	cout<<sum<<"\n";
}

----------------------------------------------------------------------------------------------------------------------------
写法二:模拟年份

#include<bits/stdc++.h>
using namespace std;
int r[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int x = 3;
int sum = 0;
bool check(int x)
{
	if (x % 4 == 0 && x % 100 != 0 || x % 400 == 0)return true;
	else return false;
}
int main()
{
	int year;
	scanf("%d", &year);
	int f = 0;
	for (int i = 1998; i < year; i++)
	{
		f += 365;
		if (check(i))f++;
	}
	int h = f % 7;
	x += h;
	if (x % 7 == 0)x = 7;
	if (check(year))r[2] = 29;
	for (int j = 1; j <= 12; j++)
	{
		for (int k = 1; k <= r[j]; k++)
		{
			x++;
			int h = x % 7;
			if (h == 0)x = 7;
			else x = h;
			if (k == 13 && x == 5)
				sum++;
		}
	}
	printf("%d\n", sum);
}

----------------------------------------------------------------------------------------------------------------------------
写法三:模拟每月

#include<bits/stdc++.h>
using namespace std;
int r[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int x = 3;
int sum = 0;
bool check(int x)
{
	if (x % 4 == 0 && x % 100 != 0 || x % 400 == 0)return true;
	else return false;
}
int main()
{
	int year;
	scanf("%d", &year);
	for (int i = 1998; i <= year; i++)
	{
		if (check(i))r[2] = 29;
		else r[2] = 28;
		for (int j = 1; j <= 12; j++)
		{
			for (int k = 1; k <= r[j]; k++)
			{
				x++;
				int h = x % 7;
				if (h == 0)x = 7;
				else x = h;
				if (i == year && k == 13 && x == 5)
					sum++;
			}
		}
	}
	printf("%d\n", sum);
}

----------------------------------------------------------------------------------------------------------------------------

6、试题 算法训练 和为T
在这里插入图片描述
解析:
二进制选取情况,第i位为1就选a[i],为0就不选a[i]。
由于每种选取情况必须选一个,即不能出现都没有选取的情况(二进制:0)。
总选取情况从1到(1<<n)中所有情况。
时间复杂度(O(2^n*n))由于数据范围(1<=n<=22)所以时间是够用的,不必担心。

#include<bits/stdc++.h>
using namespace std;
int n,m,num;
int a[25];
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    cin>>m;
    for(int i=1;i<(1<<n);i++){
        int x=i;
        int sum=0;
        for(int j=0;j<n;j++){
            if(x&(1<<j)) sum+=a[j];
        }
        if(sum==m){
            num++;
            for(int j=0;j<n;j++){
                if(x&(1<<j)) cout<<a[j]<<" ";
            }      
            puts("");      
        }
    }
    cout<<num<<"\n";
}

----------------------------------------------------------------------------------------------------------------------------
总结
1、本场题目较水,平时多刷题的同学应该深有体会。
2、某些特定类型的题目都要一些便捷的解法,平时可以多进行专题训练。
3、学习虽然重要,但还是得加强身体锻炼。比赛长达4小时,有的长达5小时,这还真不是一件容易的事。加强锻炼,在比赛等其他方面才更有优势。(抄上篇的,编不出了)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值