洛谷做过的一些题解


前排注意:本文为博主自己的学习记录!!!有些代码参考了其他用户的代码,并都标明了来处!

晶晶赴约会

题目描述

晶晶的朋友贝贝约晶晶下周一起去看展览,但晶晶每周的 1 , 3 , 5 1,3,5 1,3,5 有课必须上课,请帮晶晶判断她能否接受贝贝的邀请,如果能输出 YES;如果不能则输出 NO

输入格式

输入有一行,贝贝邀请晶晶去看展览的日期,用数字 1 1 1 7 7 7 表示从星期一到星期日。

输出格式

输出有一行,如果晶晶可以接受贝贝的邀请,输出 YES,否则,输出 NO。注意 YESNO 都是大写字母!

样例 #1

样例输入 #1

2

样例输出 #1

YES

题解

思路

直接判断输入输出,使用 C 语言

代码如下

#include<stdlib.h>
#include<stdio.h>
int main()
{
	int data;
	scanf("%d",&data);
	if(data%2 == 1 && data!=7)//判断是否为周三和周五
	printf("NO\n");
	else
	printf("YES\n");

	return 0;
}

数字统计

题目描述

请统计某个给定范围 [ L , R ] [L,R] [L,R] 的所有整数中,数字 2 2 2 出现的次数。

比如给定范围 [ 2 , 22 ] [2,22] [2,22],数字 2 2 2 在数 2 2 2 中出现了 1 1 1 次,在数 12 12 12 中出现 1 1 1 次,在数 20 20 20 中出现 1 1 1 次,在数 21 21 21 中出现 1 1 1 次,在数 22 22 22 中出现 2 2 2 次,所以数字 2 2 2 在该范围内一共出现了 6 6 6 次。

输入格式

输入共 1 1 1 行,为两个正整数 L L L R R R,之间用一个空格隔开。

输出格式

输出共 1 1 1 行,表示数字 2 2 2 出现的次数。

样例 #1

样例输入 #1

2 22

样例输出 #1

6

样例 #2

样例输入 #2

2 100

样例输出 #2

20

提示

$ 1<L,R<10000 $。

题解

思路

使用 for 循环表示范围 [ L , R ] [L,R] [L,R] 的所有整数,数字 2 2 2 出现次数通过对 10 10 10 取余判断

代码及注释如下

#include<iostream>
using namespace std;
int main()
{
	int L, R;
	cin >> L >> R;
	int sum = 0;//sum为计数器
	for(int i = L; i <= R; i++)
	{
		int j = i;
		while(j)
		{
			if(j%10 == 2)//数字2出现
				sum++;//sum+1
			j/=10;
		}
	}
	cout << sum;
	return 0;
}

二进制分类

题目描述

若将一个正整数化为二进制数,在此二进制数中,我们将数字 1 1 1 的个数多于数字 0 0 0 的个数的这类二进制数称为 A A A 类数,否则就称其为 B B B 类数。

例如:

( 13 ) 10 = ( 1101 ) 2 (13)_{10}=(1101)_2 (13)10=(1101)2,其中 1 1 1 的个数为 3 3 3 0 0 0 的个数为 1 1 1,则称此数为 A A A 类数;

( 10 ) 10 = ( 1010 ) 2 (10)_{10}=(1010)_2 (10)10=(1010)2,其中 1 1 1 的个数为 2 2 2 0 0 0 的个数也为 2 2 2,称此数为 B B B 类数;

( 24 ) 10 = ( 11000 ) 2 (24)_{10}=(11000)_2 (24)10=(11000)2,其中 1 1 1 的个数为 2 2 2 0 0 0 的个数为 3 3 3,则称此数为 B B B 类数;

程序要求:求出 1~n 之中( 1 ≤ n ≤ 1000 1 \le n \le 1000 1n1000),全部 A , B A,B A,B 两类数的个数。

输入格式

输入 n n n

输出格式

一行,包含两个整数,分别是 A A A 类数和 B B B 类数的个数,中间用单个空格隔开。

样例 #1

样例输入 #1

7

样例输出 #1

5 2

题解

思路

该题要提前掌握将十进制转换为二进制的方法。

由题意可知只需判断二进制下数字 0 0 0 与数字 1 1 1 的出现次数,因此不必将十进制数字转换为二进制数字;函数 Judge_A_B 判断 A 类还是 B 类数,主函数对函数 Judge 的返回值进行计数,最后输出。

代码及注释如下

#include<stdio.h>
#include<stdlib.h>
int Judge_A_B(int n)//判断A类数还是B类数
{
	int a, num0 = 0, num1 = 0;//num0 与 num1 计数字1和数字0出现的次数
	while(n > 0)
	{
		a = n%2;
		n = n/2;//此行与上一行的作用是将十进制转换为二进制
		if(a==1)
		num1++;
		else
		num0++;
	}
	if(num1 > num0)
	return 1;
	else
	return 0;
}

int main()
{
	int n, i, numA = 0, numB = 0;
	scanf("%d", &n);
	for(i = 1; i <= n; i++)
	{
		if(Judge_A_B(i))
		numA++;
		else
		numB++;
	}
	printf("%d %d", numA, numB);
	return 0;
}

找第一个只出现一次的字符

题目描述

给定一个只包含小写字母的字符串,请你找到第一个仅出现一次的字符。如果没有,输出 no

输入格式

一个字符串,长度小于 1100 1100 1100

输出格式

输出第一个仅出现一次的字符,若没有则输出 no

样例 #1

样例输入 #1

abcabd

样例输出 #1

c

样例 #2

样例输入 #2

aabbcc

样例输出 #2

no

题解

思路

利用字母与数字的 ASCII 码关系,建立 s[]数组统计不同字母出现的次数,最后输出 s[]=1 时的字母。

代码及注释如下

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char str[100000];
	int i, s[27]={0};//s[]统计不同小写字母出现次数
	gets(str);
	int len = strlen(str);
	for(i = 0; i < len; i++)
	{
		if(str[i]>='a'&&str[i]<='z')
		s[str[i]-'a']++;
	}
	for(i = 0; i < len; i++)
	{
		if(s[str[i]-'a'] == 1)
		{
			printf("%c", str[i]);
			return 0;
		}
	}
	printf("no");
	return 0;
}

黑白棋子的移动

题目描述

2 n 2n 2n 个棋子排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为 n = 5 n=5 n=5 的情况:

○○○○○●●●●●

移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如 n = 5 n=5 n=5 时,成为:

○●○●○●○●○●

任务:编程打印出移动过程。

输入格式

一个整数 n n n

输出格式

若干行,表示初始状态和每次移动的状态,用"o"表示白子,"*“表示黑子,”-"表示空行。

样例 #1

样例输入 #1

7

样例输出 #1

ooooooo*******--
oooooo--******o*
oooooo******--o*
ooooo--*****o*o*
ooooo*****--o*o*
oooo--****o*o*o*
oooo****--o*o*o*
ooo--***o*o*o*o*
ooo*o**--*o*o*o*
o--*o**oo*o*o*o*
o*o*o*--o*o*o*o*
--o*o*o*o*o*o*o*

提示

$ 4\leq n\leq 100$

题解

思路

此题使用递归,观察示例,n = 4 时是递归的结束条件,因此写出以下代码。

代码及注释如下

#include<bits/stdc++.h>
using namespace std;
char a[1000];
int n, end;
void print()
{
	for(int i =1; i<=2*n+2; i++)
		printf("%c",a[i]);
	printf("\n");
}
void move(int n)
{
	for(int i = 0; i < 2; i++)
	{
		a[end+i] = a[n+i];
		a[n+i] = '-';
	}
	end = n;
	print();
}
void remove(int n)
{
	if(n == 4)
	{
		move(4);
		move(8);
		move(2);
		move(7);
		move(1);
	}else{
		move(n);
		move(2*n-1);
		remove(n-1);
	}
}

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++)
		a[i] = 'o';
	for(int i = n+1; i <= n*2 ; i++)
		a[i] = '*';
	end = n*2+1;
	a[end] = a[end+1] = '-' ;
	print();
	remove(n);
	return 0;
}

[NOIP2001 普及组] 最大公约数和最小公倍数问题

题目描述

输入两个正整数 x 0 , y 0 x_0, y_0 x0,y0,求出满足下列条件的 P , Q P, Q P,Q 的个数:

  1. P , Q P,Q P,Q 是正整数。

  2. 要求 P , Q P, Q P,Q x 0 x_0 x0 为最大公约数,以 y 0 y_0 y0 为最小公倍数。

试求:满足条件的所有可能的 P , Q P, Q P,Q 的个数。

输入格式

一行两个正整数 x 0 , y 0 x_0, y_0 x0,y0

输出格式

一行一个数,表示求出满足条件的 P , Q P, Q P,Q 的个数。

样例 #1

样例输入 #1

3 60

样例输出 #1

4

提示

P , Q P,Q P,Q 4 4 4 种:

  1. 3 , 60 3, 60 3,60
  2. 15 , 12 15, 12 15,12
  3. 12 , 15 12, 15 12,15
  4. 60 , 3 60, 3 60,3

对于 100 % 100\% 100% 的数据, 2 ≤ x 0 , y 0 ≤ 10 5 2 \le x_0, y_0 \le {10}^5 2x0,y0105

【题目来源】

NOIP 2001 普及组第二题

题解

思路

此题要运用到最大公约数*最小公倍数等于所求两数 x,y 之积的知识以及欧几里得算法。

此题利用 for 循环 x 从最大公约数循环到最小公倍数,则 y = 最大公约数*最小公倍数/x。

所以我们的判断条件为:gcd(x,y)是否等于最大公约数。

代码及注释如下

#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)//运用欧几里得算法
//求出最大公约数
{
	int r;
	while(b)
    {
        r = a % b;
        a = b;
        b = r;
    }
    return a;
}
int main()
{
	int x, y, cnt = 0;//cnt统计
	cin >> x >> y;
	int max = x > y? x:y;
	int min = x <= y? x:y;
	for(int i = min; i <= max; i++)
	{
		if(x*y % i == 0)
		{
			if(gcd(i, x*y/i) == x)
			cnt++;
		}
	}
	cout << cnt;
	return 0;
}

B 进制星球

题目背景

进制题目,而且还是个计算器~~

题目描述

话说有一天,小 Z 乘坐宇宙飞船,飞到一个美丽的星球。因为历史的原因,科技在这个美丽的星球上并不很发达,星球上人们普遍采用 B(2<=B<=36)进制计数。星球上的人们用美味的食物招待了小 Z,作为回报,小 Z 希望送一个能够完成 B 进制加法的计算器给他们。 现在小 Z 希望你可以帮助他,编写实现 B 进制加法的程序。

输入格式

共 3 行第 1 行:一个十进制的整数,表示进制 B。第 2-3 行:每行一个 B 进制数正整数。数字的每一位属于{0,1,2,3,4,5,6,7,8,9,A,B……},每个数字长度<=2000 位。

输出格式

一个 B 进制数,表示输入的两个数的和。

样例 #1

样例输入 #1

4
123
321

样例输出 #1

1110

提示

进制计算器

题解

思路

参考了 CSDN 用户“代码搞起来”的文章及代码

1.将对应数字与字母转换成十进制对应数字存放在 a 与 b 数组中
2.高精度加法
3.最后字符转换(大于9的转换为A、B、C)逆序输出

收获

由本题学习到了高精度加法的用法,当有非常大的整数无法用最大 long long 的范围存储时,我们可以使用到数组来储存一个数,用数组的每一位来储存那个数字上的一位,也就是说,用一个长度为 n 的数组记录一个 n 位数字。

高精度加法几个注意点:

  1. 如果最高位大于 n 进制,表示可以向前再进位
  2. 以防 最高位是 0 的情况
  3. 输出,注意是从后往前,然后大于 10 还要转换成对应字母

代码及注释如下

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000;
int n;
string x,y;
int a[maxn],b[maxn],c[maxn];

int main(){
	cin>>n;
	cin>>x>>y;
	int lena = x.size();
	int lenb = y.size();
	for(int i=0;i<lena;i++){//将对应数字与字母转换成对应数字存放在数组中
		if(x[i] >='0' &&x[i] <='9')
		a[lena -i] = x[i] -'0';
		else if(x[i] >='A' && n>=10)
		a[lena-i] = x[i] -'A'+10;
	}
	for(int i=0;i<lenb;i++){
		if(y[i] >='0' &&y[i] <='9')
		b[lenb -i] = y[i] -'0';
		else if(y[i] >='A' && n>=10)
		b[lenb-i] = y[i] -'A'+10;
	}
	int maxlen = lena>lenb?lena:lenb;
	for(int i=1;i<=maxlen;i++){
		c[i] += a[i] + b[i];
		c[i+1] = c[i]/n;
		c[i] %= n;
	}
	maxlen++;
	//如果最高位大于n进制,表示可以向前再进位
	while(c[maxlen] >=n){
		c[maxlen+1] = c[maxlen]/n;
		c[maxlen] %= n;
		maxlen++;
	}
	//以防 最高位是 0的情况
	while(c[maxlen]==0 && maxlen >1){
		maxlen--;
	}
	//输出,注意逆序输出,然后大于10还要转换成对应字母
	for(int i=maxlen;i>=1;i--){
		if(c[i]>=10){
			cout<<(char)(c[i] +'A' -10);
		}else{
			cout<<c[i];
		}
	}

	return 0;
}


[NOIP2006 普及组] 开心的金明

题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 N N N 元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的 N N N 元。于是,他把每件物品规定了一个重要度,分为 5 5 5 等:用整数 1 − 5 1-5 15 表示,第 5 5 5 等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过 N N N 元(可以等于 N N N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第 j j j 件物品的价格为 v [ j ] v[j] v[j],重要度为 w [ j ] w[j] w[j],共选中了 k k k 件物品,编号依次为 j 1 , j 2 , … , j k j_1,j_2,…,j_k j1,j2,,jk,则所求的总和为:

v [ j 1 ] × w [ j 1 ] + v [ j 2 ] × w [ j 2 ] + … + v [ j k ] × w [ j k ] v[j_1] \times w[j_1]+v[j_2] \times w[j_2]+ …+v[j_k] \times w[j_k] v[j1]×w[j1]+v[j2]×w[j2]++v[jk]×w[jk]

请你帮助金明设计一个满足要求的购物单。

输入格式

第一行,为 2 2 2 个正整数,用一个空格隔开: n , m n,m n,m(其中 N ( < 30000 ) N(<30000) N(<30000) 表示总钱数, m ( < 25 ) m(<25) m(<25) 为希望购买物品的个数。)

从第 2 2 2 行到第 m + 1 m+1 m+1 行,第 j j j 行给出了编号为 j − 1 j-1 j1 的物品的基本数据,每行有 2 2 2 个非负整数 $ v p$(其中 v v v 表示该物品的价格 ( v ≤ 10000 ) (v \le 10000) (v10000) p p p 表示该物品的重要度( 1 − 5 1-5 15)

输出格式

1 1 1 个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值 ( < 100000000 ) (<100000000) (<100000000)

样例 #1

样例输入 #1

1000 5
800 2
400 5
300 5
400 3
200 2

样例输出 #1

3900

提示

NOIP 2006 普及组 第二题

题解

思路

参考了CSDN用户"Microstrong0305"的“动态规划学习-【0-1背包问题】”一文
以及CSDN用户“密码锁”的”开心的金明(动态规划 dp C++)“一文
以及知乎用户“代码随想录”的“咱就把0-1背包问题讲个通透!”一文

1000 5
800 2  1600
400 5  2000
300 5  1500
400 3  1200
200 2   400

该题需要动态规划的知识

代码及其注释

#include<bits/stdc++.h>
using namespace std;
int f[200000],v[30],w[30];//v[]数组是价格,w[]数组为重要度
int max(int x,int y){
	return x>y?x:y;
}
int main()
{
	int n,m;
	cin >> m >> n;
	for(int i = 1; i <= n;i++)
		cin >> v[i]>> w[i];
	for(int i = 1; i<= n;i++)
	{
		for(int j = m; j >= v[i];j--)
		{
			f[j] = max(f[j],f[j-v[i]]+w[i]*v[i]);//动态规划状态转化方程
		}
	}
	cout<< f[m];
	return 0;
}	

其实最后一题的动态规划我并不是太理解,还需要学习和理解
不过最近是期末周所以比较忙,可能暑假把这部分完成。(绝不鸽!!!)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值