2022NIT 蓝桥杯校赛 简单题解
A.考试周
- if或者switch都可以,签到题,不会写的话建议重修C语言…
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
if(n == 1) printf("Kun were studying Higher mathematics\n");
else if(n == 2) printf("Kun were studying Linear algebra\n");
else if(n == 3) printf("Kun were studying Principle of computer composition\n");
else if(n == 4) printf("Kun were studying Database system concept\n");
else if(n == 5) printf("Kun were studying Data structures and algorithms\n");
else
{
printf("Kun were playing basketball\n");
}
return 0;
}
B.01串
- 斐波那契数列,其实只要例举n的1 2 3 4…,就可以发现一些规律了,这里来讲一讲常规的思考方式:首先用f(k)表示表示n=k时X字符串的数量,那么第k位有两种情况:0和1,假如第k位为1,那么前一位不管是多少都是合法的,所以就有f(k-1)个X字符串,假如为0,那么前一位就必须是1才能合法,而前一位是1时就有f(k-2)个X字符串。把两种情况合在一起就是f(k)=f(k-1)+f(k-2),即斐波那契数列
- 代码上也有细节,首先当n过大,肯定是超出了int的范围,题目也要求结果模200003,这个也是需要注意的
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long int LL;//使用long long int类型
int main(){
int n;
scanf("%d",&n);
LL a = 1 , b = 2;
if(n == 1) printf("%d\n",1);
else if(n == 2) printf("%d\n",2);
else
{
LL y = 0;
for(int i = 3 ; i <= n ; i ++ )
{
y = (a + b)%200003;
a = b;
b = y;
}
printf("%lld\n",y);
}
return 0;
}
C.得分
- 比较简单的字符串模拟
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
char a[100];
scanf("%s",a);
int l = strlen(a);
int ans = 0;
for(int i = 0; i < l ; i ++ )
{
int no = 0;
while(a[i] == 'O')
{
no++;
ans += no;
i++;
}
}
printf("%d\n",ans);
}
return 0;
}
D.涂色
- 由题意可知最后一笔画一定是完整的一行或者一列,我们只需要判断方格图是否存在完整的行或者列就行了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
char g[8][8];
int main()
{
for(int i = 0 ; i < 8 ; i ++ )
scanf("%s",g[i]);
for(int i = 0 ; i < 8 ; i ++ )
{
int j;
for(j = 0 ; j < 8 ; j ++ )
if(g[i][j] != 'R')
break;
if(j >= 8)
{
printf("R\n");
break;
}
int k;
for(k = 0 ; k < 8 ; k ++ )
if(g[k][i] != 'B')
break;
if(k >= 8)
{
printf("B\n");
break;
}
}
return 0;
}
E.捉迷藏
就是求两个点之间的连线上有没有其它点
根据直线在平面直角坐标系上斜率的定义,点(x,y)在点(x1,y1)和点(x2,y2)所确定的线段上,当且仅当(x-x1):(y-y1)=(x-x2):(y-y2)=(x1-x2):(y1-y2)(范围x1<=x<=x2,y1<=y<=y2)
由此,我们可以得知,两个点之间存在其它的点的话,必然有(x-x1):(y-y1)=(x-x2):(y-y2),因为x,y,x1,y1,x2,y2都是整数,那么(x-x1),(y-y1),(x-x2),(y-y2),(x1-x2),(y1-y2)必然都是整数,且他们的比值相等。易证,如果存在这样的一组数,那么gcd(abs(x1-x2),abs(y1-y2))!=1,所以,我们只需求出gcd的值。
gcd即是最大公因数,辗转相除法求得
#include<iostream>
#include<cstdio>
using namespace std;
int n,ax,ay,bx,by;
int gcd(int x,int y)
{
if(y==0) return x;
else return (gcd(y,x%y));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&ax,&ay,&bx,&by);
if(gcd(abs(ax-bx),abs(ay-by))==1) printf("DANGER\n");
else printf("SAFE\n");
}
return 0;
}
F.篮球
- 二分算法,建议先去写计协公告题单里的二分那几道,可能会好理解一点,其实题目已经提示了“求最大值的最小值”,这里就可以开始考虑是否要二分这个最小值了
- 同时由于数据范围的原因,也要注意long long int之类的,就不多提了
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long int LL;
const int N = 1e5 + 10;
LL a[N];
int n,m;
bool check(LL mid)
{
int cnt = 0;
LL res = 0;
for(int i = 1 ; i <= n ; i ++ )
{
if(a[i] > mid)
return 0;
if(res + a[i] > mid)//如果这一段超过了我们当前规定的最大值mid,那就必须分段了,最大值就是不是mid
{
res = a[i];
cnt++;//cnt记录的是段数
if(cnt > m - 1)
return 0;
}
else res += a[i];
}
return 1;
}
int main()
{
scanf("%d %d",&n,&m);
LL l = 0 ,r = 0;
for(int i = 1 ; i <= n ; i ++ )
{
scanf("%lld",&a[i]);
r += a[i];
}
while(l < r)
{
LL mid = (l + r) / 2;
if(check(mid))
r = mid;
else
l = mid + 1;
}
printf("%lld\n",l);
}
G.素数环
- 深度优先搜索,建议先去写计协公告题单里的深度优先搜索那几道,可能会好理解一点
- 一道非常经典的DFS题,在原题的基础上对于输入和测试数据都简化了很多
- 答案可以直接看这个,附带讲解:UVA524:素数环
H.KTV
- 01背包问题,每首歌曲相当于物品,歌曲的长度相等于物品重量,每个歌曲的价值为1
- 有几个细节需要注意,第一个就是必须要满足歌曲数量最大,再去考虑时间。还有就是要在“时间结束前”唱额外的那首歌,也就是说假如有100秒时间,有两首歌一首是40秒一首是60秒,其实是不可以同时唱的,因为题目规定必须要唱额外的那首歌,所以至少得预留一秒给这首歌,一首40秒和一首59秒就可以。以及对于dp数组的初始化用的是-1而不是0,主要原因是对于第一首的选取问题,赋值0的话会出现决策失误的情况。题目也规定了不能出现空窗期,所以必须是连续唱歌
#include<iostream>
#include<cstring>
using namespace std;
int T,t,n,a[510],dp[510][500*180+10];
int main(){
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[0][0]=0;
for(int i=1;i<t;i++)dp[0][i]=-1;
int ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<t;j++){
dp[i][j]=dp[i-1][j];
if(j>=a[i]&&dp[i-1][j-a[i]]>=0)
dp[i][j]=max(dp[i][j],dp[i-1][j-a[i]]+1);
ans=max(ans,dp[i][j]);
}
}
for(int j=t-1;j>=0;j--)
if(dp[n][j]==ans){
printf("%d %d\n",ans+1,j+219);
break;
}
return 0;
}
J.油饼
- 贪心和选择排序的思想,我们可以把每一次的最大一位数都给转到最上面。具体的代码细节有点麻烦
I.回家
- 最短路径+二分:最短路径使用堆优化版Dijistra算法,SPFA会被卡,别问我怎么知道的
- 没有学过数据结构-图论不建议深究本题,答案在这里:通往奥格瑞玛的道路