SICNU-ACM第一次蓝桥选拔模拟赛(acm血泪史~~~~)

太烦了 真的真的真的 为啥要在危险的地方蹦跶嘛!!!
比赛补题链接
在这里插入图片描述
比赛成绩在这里插入图片描述

J 题 奖杯争夺赛

先说说这个题!!!!
(原题在今年的上海理工蓝桥练习赛)链接
蓝桥 属于常考的 DP题目
真的 我一看 不就是动归嘛 还是太狂妄 太大意了
竟然觉得 f【-1】【0】这样的 也没啥 完全不觉得在超限的范围 要遭
如果有i-1 那就要数组下标最好从1开始
就比如 f【-1】【0】就是随机值 !!!
在这里插入图片描述
在这里插入图片描述
DP版AC代码

#include<bits/stdc++.h>
using namespace std;
int f[10010][10010];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    //不放心 就
    //for(int i = 0;i<=m;i++) f[0][i] = 0;
    //for(int i = 0;i<=n;i++) f[i][0] = 0;
    for(int i = 1; i <=n;i++){
        for(int j = 1;j <=m;j++){
            scanf("%d",&f[i][j]);
        }
    }
    for(int i = 1; i <=n;i++){
        for(int j = 1;j <=m;j++){
            f[i][j] += max(f[i-1][j],f[i][j-1]);
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

A.(填空题)冒泡 计算交换次数

冒泡的原理就是 每一趟把 最大的往后挪
因为是完全逆序的 所以每一次都要交换

计算程序:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int ans = 0;
	for(int i = 2021;i>=1;i--){
		ans += i-1;
	}
	cout<<ans;
	return 0;
}

答案:在这里插入图片描述

B. (填空题)手指计数

描述:
茜学姐发现,一只手能从0数到31,两只手能从0数到1023,现在问你有十个人,他们最多能数到多少?
输入:

输出:
这是一道填空题,你只需要填入正确的答案即可,不要有任何多余的字符


解析:
0到31 正好是2的5次方==32个 那么0~1023 正好是2的10次方个
那么 十个人就是2的100次方

思路1:
python的暴力解法…直接进行N次方计算

i=100
a=2**i-1
print a

答案:
在这里插入图片描述

C.(填空题)欢欢不想爆零

就是数零的个数即为数 因数5的个数。
答案:
在这里插入图片描述

D.(填空题)斐波拉七

描述:
由于晴晴看到7就头疼,所以他将斐波拉契数改编为斐波拉七数。
斐波拉七同样满足 Fib[i] = Fib[i -1] + Fib[i - 2],只不过在从头到尾的计算过程中 将所有7都去掉。(数据保证合理并且不会出现单个7或者全7的情况)
已知 前两个数都是1
请输出第2021个数
输入:

输出:
这是一道填空题,你只需要填入正确的答案即可,不要有任何多余的字符。

求解程序:

#include<bits/stdc++.h>
using namespace std;
long long f[10010],arr[10010]; 
int quqi(int x){
	int cnt = 0;
	//分解存储  加 判断去7
	while(x){
		int res = x%10;
		if(res!=7) arr[++cnt] = res;
		x /=10; 
	}
	long long t = 1,ans = 0;
	for(int i = 1; i <= cnt;i++){
		ans += arr[i]*t;
		t*= 10;
	}
	return ans;
}
int main(){
	int ans = quqi(1771271);
	f[1]= 1,f[2]= 1;
	for(int i = 3;i<=2021;i++){
		f[i] = quqi(f[i-1] + f[i-2]);
	}
	cout<<f[2021]<<endl;
	return 0;
}

明明代码思路都是对的!! 错了 可能是quqi 函数 写得真的挺混乱的 尤其是cnt的用法
要仔细啊!!
答案:
在这里插入图片描述

E. (填空题)神奇汉诺塔【递推和枚举】

(递推和枚举)
描述:
汉诺塔问题,条件如下:
1、这里有A、B、C和D四座塔。
2、这里有20个圆盘.。
3、每个圆盘的尺寸都不相同。
4、所有的圆盘在开始时都堆叠在塔A上,且圆盘尺寸从塔顶到塔底逐渐增大。
5、我们需要将所有的圆盘都从塔A转移到塔D上。
6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。
请你求出将所有圆盘从塔A移动到塔D,所需的最小移动次数是多少。


解析:
将汉诺塔中的3跟柱子改为4根。
传统的3给汉诺塔的方程是:

f[i]=f[i−1]×2+1

思路就是:
用三个 求出四个的递推式
要对 先拿出的j个使变为三个塔 要枚举j 看j为多少的时候能取得最小的值
出题人的解析
解题代码:

#include<iostream>
#define Inf 1e9
using namespace std;
int f[5][20];
int main(){
    f[3][1]=f[4][1]=1;
    for(int i=2;i<=20;i++){
        f[3][i]=2*f[3][i-1]+1;
        f[4][i]=Inf;
    }
    cout<<1<<endl;
     for (int i=2;i<=20;i++)
    {
        for (int j=1;j<=i;j++)
         f[4][i]=min(f[4][j]*2+f[3][i-j],f[4][i]);
        printf("%d:  %d\n",i,f[4][i]);
    }
    
    return 0;
}

答案:
在这里插入图片描述

F.(填空题)分解数

把 20192019分解成33个各不相同的正整数之和,
并且要求每个正整数都不包含数字22和44,
一共有多少种不同的分解方法?
注意交换33个整数的顺序被视为同一种方法,例如1000+1001+181000+1001+18和1001+1000+181001+1000+18被视为同一种。
(比赛时填空题只要求给出答案)
输入

输出
输出有多少种不同的分解方法。


暴力枚举 跑个十多秒 就出来了【真的很无语!!】
解题代码:

#include<bits/stdc++.h>
using namespace  std;
int  qusi(int x){
	while(x){
		int t = x%10;
		if(t==2||t==4) return 0;
		x /= 10;
	}
	return 1;
}
int main(){
	int cnt = 0;
	for(int i = 2019-1;i>0;i--){
		for(int j = i-1;j>0;j--){
			for(int x = j-1;x>0;x--){
				if(qusi(i)&&qusi(j)&&qusi(x)&&(x+i+j)==2019){
					cnt++;
				}
			}
		}
	}
	cout<<cnt;
	return 0;
} 

答案:
在这里插入图片描述

G.(编程题)王者周年庆(思维)

在这里插入图片描述
解析:
这是一个找能够组成的 最大相邻相等字母个数 和最小相邻相等个数的题
所以 只要给定a b c三类字符的数量 这些字符能存在的相邻相等的位数就只能在 最大能做到的位数 和最小能做到的位数之间
最优的策略是 每一类的字符都是相邻的 这也就最大 为 max(0,a-1)+max(0,b-1)+max(0,c-1)
然他尽量不存在相邻相等的情况 采用在最多的字母间插入其他两种字母,故而最小值为
max(a,max(b,c))-1 -(a+b+c-max(a,max(b,c)))
解题程序:

#include<bits/stdc++.h>
using namespace std;
int main(){
  int T;
  cin>>T;
  while(T--){
  	int a,b,c,d;
    cin>>a>>b>>c>>d;
    int sum = a+b+c;
    if(max(0,a-1)+max(0,b-1)+max(0,c-1)>=d&&max(max(a,b),c) - 1 - (sum-max(max(a,b),c)) <= d)
    cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
  }
	return 0;
}

I.(编程题)未成年数

解析:
就是判断十七进制是否是回文数
正好 在判断回文前 要转进制 这样直接把每一位的值存到数组里面
然后再 循环判断一下 回文就行了
解题代码:

#include<bits/stdc++.h>
using namespace std;
int arr[1000010]; 
int check(int n){
	int cnt = 0;
	while(n){
		arr[++cnt] = n%17;
		n /= 17; 	
	}
	for(int i = 1,j = cnt; i <= cnt/2;i++,j--){
		if(arr[i]!=arr[j]) return 0;
	}
	return 1;
}
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	int cnt = 0;
	for(int i = a;i<=b;i++){
		if(check(i)) cnt++;
	}
	cout<<cnt; 
	return 0;
} 

K.(编程题)火车进站(队列)

描述
随着时代的高速发展,火车行业发展的愈加迅速。小K同学对于火车相当的痴迷,于是他来到一个火车站进行统计调查。
他想统计当前正在进站的火车以及从当前时刻开始计算,过去 2424 小时(即 8640086400 秒)内进站的火车总共由多少个不同的车厢制造商制造。
假设未来的火车每节车厢可以由不同的厂商制造且每列火车瞬间进站(即进站时间不计),车厢的制造商用正整数编号表示。
请你帮他计算每次统计出的不同制造商数量。
题目原型链接

https://www.luogu.com.cn/problem/P2058

【重点!!!这是一个数据结构的题】
同样的 我们用数组来模拟队列
acwing的 模板题链接:https://www.acwing.com/problem/content/469/
解题代码:

#include<iostream>
using namespace std;
const int N = 300005;
int n,t,k,i,cnt,ans,tt[N],x[N],num[N];
int main(){
    cin>>n;
    while(n--){
        cin>>t>>k;
        while(k--){
            tt[++cnt] = t; //记录时间
            cin>>x[cnt];//商号
            if(!num[x[cnt]]) ans++;
            num[x[cnt]]++; //记录每种商号的数目
        }
        while(t-tt[i]>=86400){
            if(!--num[x[i++]]) ans--;
            //如果在 超出时间的车上  车厢的那个商号只有一个 那势必要少一个商号  
        }
        cout<<ans<<endl;
    }
    
    return 0;
}

感悟:
优秀的经典算法就那几个
其实吧 大多数 没有 那么多那么多那么复杂的优化

大多数还是 在题意上设置障碍

L.(编程题)最佳牛围栏(贪心、优先队列、堆)

描述
蓝桥杯争夺赛为了给大家筹钱,开了一个农场。这天,有NN头小牛在畜栏中吃草。
每个畜栏在同一时间段只能提供给一头小牛吃草,因为这些小牛都很傲娇,看见别的小牛一起吃草就会不高兴地打起来!为了避免小牛们打架,所以我们可能会需要多个畜栏。
现在,给定NN头小牛和每头小牛开始吃草的时间{A}A以及结束吃草的时间{B}B,每头小牛在[A,B][A,B]这一时间段内都会一直吃草。
当两头小牛的吃草区间存在交集时(包括端点),这两头小牛不能被安排在同一个畜栏吃草,否则它们会打起来的。
求需要的最小畜栏数目和每头小牛对应的畜栏方案。
输入
第{1}1行:输入一个整数{N}N。
第{2…N+1}2…N+1行:第{i+1}i+1行输入第{i}i头牛的开始吃草时间{A}A以及结束吃草时间{B}B,数之间用空格隔开。
数据范围:
{1≤N≤50000}1≤N≤50000,
{1≤A,B≤1000000}1≤A,B≤1000000
输出
第{1}1行:输入一个整数,代表所需最小畜栏数。
第{2…N+1}2…N+1行:第{i+1}i+1行输出第{i}i头牛被安排到的畜栏编号,编号是从{1}1

输入:
5
1 10
2 4
3 6
5 8
4 7
输出:
4
1
2
3
2
4

题目原型链接:
https://www.acwing.com/problem/content/113/

解题代码:

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

typedef pair<int,int> PII;
const int N=50550;
pair<PII,int> cows[N];
int ans[N];

int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>cows[i].first.first>>cows[i].first.second;
        cows[i].second=i;
    }
    
    sort(cows,cows+n);
    priority_queue<PII,vector<PII>,greater<PII> > head;
    //greater从小到大排序,less从大到小排序
    
    for(int i=0;i<n;i++){
        auto cow=cows[i].first;
        if(head.empty()||head.top().first>=cow.first){
            PII stall={cow.second,head.size()+1};
            head.push(stall);
            ans[cows[i].second]=stall.second;
        }else{
            auto stall=head.top();
            head.pop();
            stall.first=cow.second;
            ans[cows[i].second]=stall.second;
            head.push(stall);
        }
    }
    
    cout<<head.size()<<endl;
    for(int i=0;i<n;i++) cout<<ans[i]<<endl;
    return 0;
}

有一个二分的类型题 是时候该整理整理二分了
原题链接:
https://www.acwing.com/problem/content/description/104/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值