寒假集训2023/01/12题解A-K

问题 A: 分离出整数n从右边数第k个数字,递归实现

思路:将整数作为字符串容易判断其位数与k关系。只有一位时若k=1则次数即为答案,否则第k个数不存在。k大于次数位数时第k个数不存在。其他情况递归k-1次每次使字符串长度-1(丢弃末末位字符),返回最后一位即为答案。

代码:

#include <bits/stdc++.h>
using namespace std;

char digit(string s,int k){
	if(s.length()==1){//只有一位时,k=1可返回此数,否则第k个数字不存在
		if(k==1) return s[s.length()-1];
		else return '0';
	}
	if(k>s.length()) return '0';//k超过整数位数,第k个数字不存在
	if(k>1){//递归字符串长度每次-1,k-1次后返回末尾字符
		return digit(s.substr(0,s.length()-1),k-1);
	}
	if(k==1) return s[s.length()-1];
}

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
    string s;
	int k;
	cin>>s>>k;
	char ans=digit(s,k);
	cout<<ans;

    return 0;
}

问题 B: Xu Xiake in Henan Province

思路:计数,输出对应字符串即可,没什么特别的。(但是otaku有被内涵到  笑死)

代码:

#include <bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int t;
	cin>>t;
	while(t--){
		int count=0;
		for(int i=0;i<4;i++){
			int temp;
			cin>>temp;
			if(temp!=0) count++;
		}
		if(count==0) cout<<"Typically Otaku"<<endl;
		else if(count==1) cout<<"Eye-opener"<<endl;
		else if(count==2) cout<<"Young Traveller"<<endl;
		else if(count==3) cout<<"Excellent Traveller"<<endl;
		else if(count==4) cout<<"Contemporary Xu Xiake"<<endl;
	}

    return 0;
}

问题 C: Fibonacci Sequence

思路:直接递归会超时,所以就在数组里算吧。

代码:

#include <bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int n;
	cin>>n;
	long long a[91];
	a[1]=a[2]=1;
	for(int i=3;i<=n;i++){
		a[i]=a[i-1]+a[i-2];
	}
	cout<<a[n]<<endl;

    return 0;
}

问题 D: 一只小蜜蜂

思路:可以递归,但是容易超时,还是像斐波那契数列那样先算出来比较好。当起始地点和终点相差为1的时,只有一种方法;当相差为2时,有两种方法,而除去相差为1与相差为2的情况后,其余的都可以使用前两者的方法数相加得到结果。

代码:

#include <bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int n;
    cin>>n;
    long long way[51];
    way[2]=1;way[3]=2;
    for(int i=4;i<=50;i++){
        way[i]=way[i-1]+way[i-2];//直接算出前五十个(类似斐波拉契数列)
	}
	while(n--){
		int a,b;
        cin>>a>>b;
		if(a>b) cout<<0<<endl;
        else cout<<way[b-a+1]<<endl;
    }

    return 0;
}

问题 E: 【蓝桥杯2020初赛】七段码

思路:dfs搜索所有状态,判断每种状态是否满足条件。判断的方法是把每条灯管当作一个节点,编号(a b c d e f g → 1 2 3 4 5 6 7),连边建图,对搜索出的亮灯方案使用并查集判断点亮的灯管是否在同一个集合。答案是80.

代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 10;

int ans;
int p[N];
bool st[N];
int e[N][N];

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

void dfs(int u){
	if(u == 8)	{
		for (int i = 1; i <= 7; i ++) p[i] = i;
		
		for (int i = 1; i <= 7; i ++)
			for (int j = 1; j <= 7; j ++)
				if(e[i][j] && st[i] && st[j])
					p[find(i)] = find(j);
		
		int cnt = 0;
		for (int i = 1; i <= 7; i ++)
			if(st[i] && p[i] == i)
				cnt ++;
		
		if(cnt == 1) ans ++;
		return;				
	}
	st[u] = 1;// 打开第 u 个二极管
	dfs(u + 1);
	
	st[u] = 0;// 关闭第 u 个二极管
	dfs(u + 1);
} 

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	e[1][2] = e[1][6] = 1;
	e[2][1] = e[2][7] = e[2][3] = 1;
	e[3][2] = e[3][7] = e[3][4] = 1;
	e[4][3] = e[4][5] = 1;
	e[5][4] = e[5][7] = e[5][6] = 1;
	e[6][1] = e[6][7] = e[6][5] = 1;
	e[7][2] = e[7][3] = e[7][5] = e[7][6] = 1;
	
	dfs(1);
	
	cout << ans << endl;
	return 0;
} 

问题 F: 【蓝桥杯2020初赛】平面切分

思路:在同一个平面内,如果添加一条直线,与平面所有的直线不相交,则会增加一个平面,如果与这个平面内的一条直线相交并且产生新的交点,那么就会额外增加一个平面。(也就是说,只要增加一条直线,必然多一个平面,若还与其他直线有n个交点,则会再多出n个平面)
那么我们只需对输入的每一条直线,判断是否是重边,计算当前直线与已有直线有多少个不同的交点,计算交点我们可以用set(自动去重)。

代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 1005;
typedef pair<double, double> PDD;

bool side[N]; //用来标记重边,防止重复计算交点
double a[N][2];//记录所有输入的边

int main(){
	int n;
	cin >> n;
	
	int ans = 1; //初始平面数为1
	for(int i=1;i<=n;i++){
		cin >> a[i][0] >> a[i][1];
		set<PDD> point; // 计算该直线与平面内的直线的不同交点的个数
		
		for(int j=1;j<=i-1;j++){//查找重边
			if(side[j]) continue;//已有相同直线
			if(a[i][0] == a[j][0]){
				if(a[i][1] == a[j][1]){//相同直线
					side[i] = true;
					break;
				}
				else continue;//斜率相同,平行,不用算交点
			}
			//相交直线计算交点
			double x = (a[i][1] - a[j][1]) / (a[j][0] - a[i][0]);
			double y = a[i][0] * x + a[i][1];
			point.insert({x, y});
		}
		if(!side[i]) ans += point.size() + 1;
	}
	cout << ans << endl;

	return 0;
}

问题 G: 回到学校

思路:用数组接a[n]收输入信息,再将其下标(学号)与值(进入次序)颠倒存入另一数组b[n]中,此时新数组即为按照进教室先后顺序排好的序列,输出即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int n;
	cin>>n;
	int a[n+1];
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int b[n+1];
	for(int i=1;i<=n;i++){
		b[a[i]]=i;
	}
	for(int i=1;i<=n;i++){
		cout<<b[i]<<' ';
	}

	return 0;
}

问题 H: 九九乘法表(教师版)

思路:数组记录所有九九乘法表出现的数,对输入的数循环比对即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int nn[50];
	int loc=0;
	for(int i=1;i<=9;i++){//直接把九九乘法表出现的所有数记录下来
		for(int j=1;j<=i;j++){
			nn[loc]=i*j;
			loc++;
		}
	}
	//cout<<loc<<endl;  //loc为45,所以数组开50就够
	int n;
	cin>>n;
	for(int i=0;i<loc;i++){
		if(n==nn[i]){
			cout<<"Yes"<<endl;
			return 0;
		}
	}
	cout<<"No"<<endl;

	return 0;
}

问题 I: 逃命双曲线

思路:遍历x求y,y是整数时,计算所需时间,即x+y-2,取其中最小的。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	long long k;
	cin>>k;
	long long xk=sqrt(k)+1;
	long long dmin=1000000000000;//亲身试错:INT_MAX太小了不够用
	for(long long x=1;x<=xk;x++){
		double y=(k*1.0)/(x*1.0);
		double temp=y;
		if(temp==(long long)y){
			if(x+y-2<dmin){
				dmin=x+y-2;
			}
		}
	}
	cout<<dmin<<endl;
	return 0;
}

问题 J: Dongdziz与300刀1刀999

思路:原字符ASCII码加n后,比'A'多出的部分对26取模,得到的数加上'A',利用putchar()输出即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int n;
	cin>>n;
	string s;
	cin>>s;
	for(int i=0;i<s.length();i++){
		int temp=(s[i]+n-'A')%26+'A';
		putchar(temp);
	}

	return 0;
}

问题 K: Bob和Alice(4)

思路:多次尝试之后发现,将1到n的顺序排序左移1位后得到的Mi相加值最大,而此时计算出来的Mi=i(除了i==n时,因为最大那个数对1取模为0,相当于喂狗了)。所以输入为n时,答案应为1到n-1的和。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	long long n;
	cin>>n;
	long long sum=0;
	for(int i=1;i<n;i++){
		sum+=i;
	}
	cout<<sum<<endl;

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值