刷题记录
2月15号
1.
题目
在这里,我刚开始就在z字型中卡住了,下面是图解.希望可以帮助大家理解.
这是我的代码,并不是最好的,需要10ms,最优解是4ms.
还需要优化
这里还涉及一个知识
就是这么表示分数
我当时是没有想出来的
%d/%d
就是printf出来的
思路:
1.发现规律
规律:可以看做是一个金字塔
1/1
2/1 1/2
3/1 2/2 1/3
4/1 3/2 2/3 1/4
5/1 4/2 3/3 2/4 1/5
我们可以发现
从左到右
分母:增加
分子:减小
奇数列:从左到右
偶数列:从右到左
2.然后就是代码化加上联系题目
①首先有两种情况,所以就分if-else
题目要是输入k项然后就是输出该项
②那么我们是不是要知道是第几行
1+2+3+4......
这不就是等差数列吗?
直接上公式就好
③在一行中用循环来找出第k项
可以用for
④注意一下分子分母的初始值
2.采摘苹果
#include<stdio.h>
int main()
{
int a[100];
int b,count,i;
printf("input:");
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
scanf("%d",&b);
for(i=0;i<10;i++)
{
if(30+b>=a[i])
{
count++;
}
}
printf("%d",count);
return 0;
}
优化:
这个题目很简单,但是可以对代码进行多次优化。
首先,常规读入高度和身高,这个没什么可优化的。
接下来分两步,一个是比较,一个是计算。
常规做法基本上是 if(height[i] <= H + 30)s++;
但是,对于部分要卡常的题目来说,可能会爆掉,而且每次都调用寄存器来计算 H+30,很显然是一种浪费。
首先我们可以像多数题解那样,在读入 H 之后,直接对它进行 +=30的操作。
但是实际上,比较的行为也可以简化。
if(height[i] <= H )s++; 电脑计算的时候分为三步:
-
计算 height[i] <= H 的值 (true | false)
-
调用if判断里面表达式的值是否为真
-
若真,对s进行s+=1的运算。
我们简化时可以发现,s每次加的值都是恒定的 1 。
联想到 : true == 1 , false == 0 , 我们可以直接将逻辑值的结果加给s。
也即 s+=!(H<height[i]);
CPP代码如下
#include <iostream>
using namespace std;
int height[20],H,s;
int main()
{
for(int i=0;i<10;i++)cin >> height[i];
cin >> H;
H += 30;
for(int i=0;i<10;i++)s+=!(H<height[i]);
cout << s;
}
2月16日
1.题目:校园的树(有很大的优化空间)
题目描述
某校大门外长度为 ll 的马路上有一排树,每两棵相邻的树之间的间隔都是 11米。我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 ll 的位置;数轴上的每个整数点,即 0,1,2,…,l0,1,2,…,l,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入格式
第一行有两个整数,分别表示马路的长度 ll 和区域的数目 mm。
接下来 mm 行,每行两个整数 u,vu,v,表示一个区域的起始点和终止点的坐标。
输出格式
输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。
输入输出样例
500 3 150 300 100 200 470 471
298
说明/提示
【数据范围】
- 对于 20%20% 的数据,保证区域之间没有重合的部分。
- 对于 100%100% 的数据,保证 1≤l≤1041≤l≤104,1≤m≤1001≤m≤100,0≤u≤v≤l0≤u≤v≤l。
【题目来源】
NOIP 2005 普及组第二题
开始的胡思乱想:我想的是先把输入的数据进行排序,然后在进行后面的操作。或者是合并一下区间
思路:
题目中有个难点是区间中是可以重复的,所以你用什么方式来避免或者说是解决。
那么,可能在c语言中是什么树的知识
我叫他标志
1⃣️、首先把所有的树标志为'0'
注意,在这里,我用数组的方式来存储
2⃣️、联系题目,需要输入区间
我想想到了循环。
3⃣️、由于我只要把要砍的树标志为1就可以,就算是重复也没有什么关系。这个就是其中的妙处。
2.质数分解
代码:
本题考数学。
首先要知道唯一分解定理:一个数能且只能分解为一组质数的乘积。可知,若输入的数满足题目条件,他就只能分解为两个质数的乘积。所以在比他小且大于1的自然数中,只有那两个数能整除它,之间不可能再有任何合数或质数能整除它了,因为最小的能整除它的合数已经是他本身了。
所以代码就很容易实现了
这里的意思是如果一个数是可以分解为两个质数,那么这个是只能分解一组质数,
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
for(int i=2;i<=n;++i)
if(n%i==0)
{
printf("%d",n/i);
break;
}
return 0;
}
还可以改进一下:
#include<stdio.h>
int main
()
{
int n;
scanf("%d",&n);
for(int i=2;i<=(int)sqrt((double)n);++i)
if(n%i==0)
{
printf(
"%d",n/i);
break;
}
return
0;
}
上面的做法其实取巧了
利用了一个数如果可以分解为两个质数的乘积的话,那么还有一对因数是1和本身
比如21可以分解为3和7,剩下两个的因数1和本身
题目要找的是最大的那个质数
所以我们从2开始找
i<=(int)sqrt((double)n)
这个是缩小范围
就是找这个范围的并且可以和n整除的质数
这样就可以找到最小的质因数
最后相除就好
--------------------------------------------------
还有一种思路:
比较直接:
输入一个数n
然后从2开始到n
找出一个质数m,就看n%m==0
如果等于0,那么这个就是最小的质因数
最后;用n/最小质数就好
比较复杂
#include<stdio.h>
#include<math.h>
int main()
{
int n,i,j;
scanf("%d",&n);
for(i=2;i<=n;i++)
{
int flag=1; //为什么在这里定义就可以
for(j=2;j<=(int)sqrt((double)i);j++)
{
if(i%j==0)
{
flag=0;
break;
}
}
if(flag==1) //在这里出来的是质数
{
if(n%i==0)
{
printf("%d",n/i);
break;
}
}
}
return 0;}
2月17日
p1085
代码:
1 #include<stdio.h>
2 int main()
3 {
4 int i,ret=1,m=0,a,b;
5 for(i=1;i<=7;i++)
6 {
7 scanf("%d%d",&a,&b);
8 if(m<a+b)
9 {
10 m=a+b;
11 ret=i;
12 }
13 }
14 if(m>8)
15 printf("%d\n",ret);
16 else
17 printf("0");
18 return 0;
19 }
这道题要理解题意
是先计算出七天中每天的总时间
然后,输出时间最长的那一天的星期数
如果相同时长就输出靠前的星期数
我的方法:
是利用数组,基本原理是一样的
1 #include<stdio.h>
2 int main()
3 {
4 int a[20],b[20];
5 int i,k=0,count=0;
6
7 for(i=0;i<14;i++)
8 {
9 scanf("%d",&a[i]);
10 }
11
12 //复制到b数组中
13
14 for(i=0;i<14;i=i+2)
15 {
16 b[k]=a[i]+a[i+1];
17 k++;
18 }
19
20 int max,ret;
21 max=b[0];
22
23 for(i=1;i<7;i++)
24 {
25 if(b[i]>max)
26 {
27 max=b[i];
28 ret=i+1;
29 }
30 }
31
32 if(max>8)
33 {
34 printf("%d",ret);
35 }
36 else
37 {
38 printf("0");
39 }
40 return 0;
41 }
闲话:这道题目,我刚开始理解错了,题目描述不清晰.
下面让我揭开面纱,我好好剖析一番
题目的核心:
有七个数(可能相同)
叫你找出最大的那个数字是第几个
如果有相同的话,就写出最前面的那个
我们可以设一个max值,然后就是比较
if(b[i]>max)
26 {
27 max=b[i];
28 ret=i+1;
29 }
而第几个的问题,就通过数组的底标+1就可以解决了
---------------------------------------------------------------
分析一下:
思路一:模拟
这个模拟十分清晰
以月为单位进行模拟
#include<iostream>
using namespace std;
int money,cost,mama,flag=1,monthofdeath; //money代表在津津手里的钱,cost代表花费的钱,mama代表在妈妈手里的100元的张数,flag=1代表尚未透支,monthofdeath代表死亡月份
int main ()
{
for(int i=1;i<=12;i++)
{
money+=300; //每个月津津手里的钱都会增加300
cin>>cost; //输入这个月的花销
money-=cost; // 津津手里的钱减去这个月的花销等于剩余的钱
if(money<0) //若剩余的钱小于0,
{
flag=0; //旗帜倒下,即已经透支
monthofdeath=i; //输出死亡月份
break; //终止循环
}
mama+=money/100; //剩余的钱整除100即为在妈妈手里的100元的张数
money%=100; //用100去模剩余的钱即为月底幸存的钱
}
if(flag==1) //若旗帜未倒下,即坚持到年底还没有透支
{
money+=mama*120; //剩余的钱
cout<<money;
}
else
{
cout<<-monthofdeath;
}
return 0;
}
思路二:找规律(有运气的成分)
刚刚看了一次,发现这个与思路三是一样的
#include<stdio.h>
int main()
{
int c=0,i,a[12],t=0;
for(i=0;i<12;i++)
{
scanf("%d",&a[i]);
c=(300-a[i]+c)%100; //这个是每个月最终留在手中的钱
t=(300-a[i]+t); //刚刚看了一次,发现这个与思路三是一样的,t就是累计,t最后就是总钱减去花费的钱
if(c<0)
{
printf("-%d",i+1);
break;
}
}
if(c>=0)
{
printf("%.0f",(t-c)*1.2+c);
}
return 0;
}
思路三:整体思想
这里是我做了第二中方法悟出来的
并且对很多题目都是适用的
首先,我们知道如果妈妈没有20%的利息返还的话,钱的多少是不变的(300*12)
这个是总钱数
那么上交的钱就等于总的钱-花费的-12月末剩下的钱
那么如果只要每个月都能不欠钱
就可以收到妈妈的利息
#include<stdio.h>
int main()
{
int c=0,i,a[12],sum=0;
for(i=0;i<12;i++)
{
scanf("%d",&a[i]);
sum=sum+a[i];
c=(300-a[i]+c)%100; //这个是每个月最终留在手中的钱
if(c<0)
{
printf("-%d",i+1);
break;
}
}
if(c>=0)
{
printf("%.0f",(300*12-sum-c)*1.2+c);
}
return 0;
}
2月18号
一题多解决,加上复习数字倒置问题
特别说明:从题目的数字范围可以知道,这题没有涉及700-->007的问题,因为是小数700.0--->0.007
一 字符
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 char c[17]; 6 7 int main() { 8 scanf("%s", c); 9 for(int i = strlen(c) - 1; i >= 0; --i) 10 printf("%c", c[i]); 11 return 0; 12 }
二.字符串(我没有看明白)
这道题乍一看,我很想使用 intint 和 floatfloat 结合分支语句来进行解决,可以对于小数点未免太麻烦。那么还可以用什么来解决呢?请注意,对于数字不要求运算的处理,我们基本都可以使用 字符串 来解决。
那么讲一下基本思路:
-
首先读入一个字符串(为了方便使用 stringstring )
-
接着,获取其长度,即使用 str.size()str.size() 的方法,当中 strstr 是字符串的变量名,这个函数会返回一个值,即字符串的长度
-
注意,字符串的长度比起他的最大下标( indexindex )是要大 11 的,所以倒序输出是要注意。同理,第一个字符的下标是 00 。
那么代码基本架构出来了,我们看以下代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 string a; 4 int main() 5 { 6 cin>>a; 7 for(int i=a.size()-1;i>=0;i--)cout<<a[i]; 8 return 0; 9 }
三.无赖之法
1 #include<stdio.h> 2 int main() 3 { 4 char a,b,c,d; 5 scanf("%c%c%c.%c",&a,&b,&c,&d); 6 printf("%c.%c%c%c",d,c,b,a); 7 return 0; 8 }
四.不知为什么也可以通过,这个是不符合题意的
因为700.0-->0.7
1 #include<stdio.h> 2 int main() 3 { 4 int a,b,c=0,d; 5 scanf("%d.%d",&a,&b); 6 7 while(a!=0) 8 { 9 10 d=a%10; 11 c=c*10+d; 12 a=a/10; 13 } 14 15 printf("%d.%d\n",b,c); 16 return 0; 17 }
拓展:数字倒置:
2月27号
精做三角函数题目
1,选择排序法
有关选择排序的理解
比如
一组数
4 8 9 2 17 24 5 3 21 1
要求:从小到大
4 8 9 2 17 24 5 3 21 1
从4开始比较发现2比4小
4 8 9 2 17 24 5 3 21 1
注意:"2"的位置序号j赋给了min 也就是min=j;
又回到二重循环,for(j=i+1;j<3;j++)
也就是说从2开始4 8 9 2 17 24 5 3 21 1
发现1比2小,所以min=j;(j表示1的位置)到这里表示一重循环的一次就结束了
通过选择排序,我们找到了最小的数,那么我们要交换位置,
写到这里,我突然知道了选择排序的核心:
我们拿从小到大的排序来说
首先,在一堆数中找到最小的,然后交换位置,把最小的放在第一个,
然后,去掉第一个,再去找剩下中最小的数,再交换位置
我们发现这些动作是可以通过循环完成的
这里就比较智慧地设了min
再开始时
min=i
#include<stdio.h> int main() { int a[10],i,temp,min,j; for(i=0;i<3;i++) { scanf("%d",&a[i]); } for(i=0;i<2;i++) { min=i; for(j=i+1;j<3;j++) { if(a[j]<a[min]) { min=j; } } //交换 temp=a[i]; a[i]=a[min]; a[min]=temp; } for(i=0;i<3;i++) { printf("%d",a[i]); } return 0; }
3月3号
今天,我复习了,有关杨辉三角的内容
本质就是找规律
比如直角型
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
找规律:
主对角线:都是1 第一列也是1
其他位置
a[i][j]=a[i-1][j-1]+a[i-1][j];
注意:其他位置的是控制
也就是蓝色的部分
如果用二维数组来做的话就要注意了
第一种
直角型
1 #include<stdio.h> 2 int main() 3 { 4 int a[100][100],n,i,j; 5 scanf("%d",&n); 6 7
//分情况,进行 8 for(i=0;i<n;i++) 9 { 10 a[i][0]=1; 11 a[i][i]=1; 12 } 13 14
for(i=2;i<n;i++) 15 { 16 for(j=1;j<i;j++) //注意这里是控制 直角三角形里面的数 17 { 18 a[i][j]=a[i-1][j-1]+a[i-1][j]; 19 } 20 } 21
22 for(i=0;i<n;i++) 23 { 24 for(j=0;j<=i;j++) 25 { 26 printf("%d ",a[i][j]); 27 } 28 printf("\n"); 29 } 30 return 0; 31 }
第二种
等腰三角形
思路:先大数据填进直角三角形中
然后在打印是下手脚就可以了
也就是我在打印前面加上" "(空格)就OK了
#include<stdio.h> int main() { int n,a[100][100],i,j; scanf("%d",&n); //第一种情况 for(i=0;i<n;i++) { a[i][0]=1; a[i][i]=1; } //第二种情况 for(i=2;i<n;i++) { for(j=1;j<i;j++) { a[i][j]=a[i-1][j-1]+a[i-1][j]; } } for(i=0;i<n;i++) { for(j=0;j<n-i-1;j++) { printf(" "); } for(j=0;j<=i;j++) { printf("%6d",a[i][j]); } printf("\n"); } return 0; }