前排注意:本文为博主自己的学习记录!!!有些代码参考了其他用户的代码,并都标明了来处!
晶晶赴约会
题目描述
晶晶的朋友贝贝约晶晶下周一起去看展览,但晶晶每周的
1
,
3
,
5
1,3,5
1,3,5 有课必须上课,请帮晶晶判断她能否接受贝贝的邀请,如果能输出 YES
;如果不能则输出 NO
。
输入格式
输入有一行,贝贝邀请晶晶去看展览的日期,用数字 1 1 1 到 7 7 7 表示从星期一到星期日。
输出格式
输出有一行,如果晶晶可以接受贝贝的邀请,输出 YES
,否则,输出 NO
。注意 YES
和 NO
都是大写字母!
样例 #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 1≤n≤1000),全部 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 的个数:
-
P , Q P,Q P,Q 是正整数。
-
要求 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 种:
- 3 , 60 3, 60 3,60。
- 15 , 12 15, 12 15,12。
- 12 , 15 12, 15 12,15。
- 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 2≤x0,y0≤105。
【题目来源】
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 位数字。
高精度加法几个注意点:
- 如果最高位大于 n 进制,表示可以向前再进位
- 以防 最高位是 0 的情况
- 输出,注意是从后往前,然后大于 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 1−5 表示,第 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 j−1 的物品的基本数据,每行有 2 2 2 个非负整数 $ v p$(其中 v v v 表示该物品的价格 ( v ≤ 10000 ) (v \le 10000) (v≤10000), p p p 表示该物品的重要度( 1 − 5 1-5 1−5)
输出格式
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;
}
其实最后一题的动态规划我并不是太理解,还需要学习和理解
不过最近是期末周所以比较忙,可能暑假把这部分完成。(绝不鸽!!!)