刷题记录

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++; 电脑计算的时候分为三步:

 

  1. 计算 height[i] <= H 的值 (true | false)

  2. 调用if判断里面表达式的值是否为真

  3. 若真,对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,表示一个区域的起始点和终止点的坐标。

 

输出格式

 

输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。

 

输入输出样例

 

输入 #1
500 3
150 300
100 200
470 471
输出 #1
298

 

说明/提示

 

【数据范围】

  • 对于 20%20% 的数据,保证区域之间没有重合的部分。
  • 对于 100%100% 的数据,保证 1≤l≤1041l104,1≤m≤1001m100,0≤u≤v≤l0uvl。

【题目来源】

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 结合分支语句来进行解决,可以对于小数点未免太麻烦。那么还可以用什么来解决呢?请注意,对于数字不要求运算的处理,我们基本都可以使用 字符串 来解决。

那么讲一下基本思路:

  1. 首先读入一个字符串(为了方便使用 stringstring )

  2. 接着,获取其长度,即使用 str.size()str.size() 的方法,当中 strstr 是字符串的变量名,这个函数会返回一个值,即字符串的长度

  3. 注意,字符串的长度比起他的最大下标( 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;
}

 

posted @ 2022-02-15 17:27  黑衣侠客  阅读(24)  评论(0编辑  收藏  举报