【OJ】机试指南 第一章

机试指南

第一章 从零开始

OJ 网站

  • OJ-Websites

做题结果反馈

  • Accepted

    • 答案正确
  • Wrong Answer

    • 答案错误:程序实现或者思路出现问题,也可能是数据范围边界没有考虑到
  • Runtime Error

    • 运行时错误:数组越界或者递归过深导致栈溢出
  • Presentation Error

    • 输出格式错误:一般是末尾多了或少了空格或少了换行
  • Time Limit Exceeded

    • 程序运行超时:算法不够优秀,程序运行时间过长
  • Memory Limit Exceeded

    • 运行内存超限:程序申请太大了空间,超过了题目规定的空间大小
  • Compile Error

    • 编译错误:代码存在语法错误,检查是不是选择错误的语言提交了
  • Output Limit Exceeded

    • 输出超限:程序输出过多的内容,一般是循环出了问题导致多次输出或者调试信息忘记删除了
  • Submitting

    • 提交中,等待题目结果的返回,由于判题机有性能差异所以返回结果也不一样

输入输出技巧

//输入int型变量
scanf("%d",&x);
//输入double型变量
scanf("%lf",&x);//不用float直接double
//输入char类型变量
scanf("%c",&x);
//输入字符串数组
scanf("%s",s);
//输出与输入表示方式一致
printf("%s\n",s);
  • scanf 输入解析

    • 输入日期 2020 - 03 - 21

    • int year,month,day;
      scanf("%d-%d-%d",&year,&month,&day);
      printf("%d %d %d\n",year,month,day);
      
    • 输入时间 18 : 21 : 30

    • int hour,minute,second;
      scanf("%d:%d:%d",&hour,&minute,&second);
      printf("%d %d %d\n",hour,minute,second);
      
  • scanf 和 gets

输入一行字符串带空格的话,使用 gets,scanf 遇到空格会自动结束

char s[105];
gets(s);
printf("%s\n",s);
  • getchar 和 putchar

读入单个字符和输出单个字符,一般在 scanf 和 gets 中间使用 getchar 用于消除回车 '\n' 的影响

  • 输出进制转换
int a = 10;
printf("%x\n",a);//小写十六进制输出a
printf("%X\n",a);//大写十六进制输出A
printf("%o\n",a);//八进制输出答案12
  • 输出增加前置0
int a = 5;
printf("%02d\n",a);//2代表宽度,不足的地方用0补充
输出结果 05
printf("%04d\n",a);
输出结果 0005
  • 输出保留小数
double a = 3.6;
printf("%.2lf\n",a);//2表示保留两位小数
输出结果 3.60

注:有小数输出小数,没小数输出整数,前提是输入的类型浮点类型

%g

Example:

#include 
int main(){
    
    double a = 2;
    double b = 2.5467;
    printf("a = %g\n",a);
    printf("b = %g\n",b);
    
    return 0;
} 

Test Result:

image-20200321110921091
  • long long 的使用

很多情况下的计算会超过 int,比如求 N!,N 比较大的时候 int 就存不下了,这个时候我们就要使用 long long。

注:int 取值范围:-1e9 到 1e9,long long 取值范围:-1e18 到 1e18

long long x;
scanf("%11d",&x);
printf("%lld\n",x);
  • 字符的 ASCII 码
printf("%d\n",'a');

注:若遇到需要 ASCII 码的题目,记住 char 字符和 int 值是可以相互转化的。

  • cin 和 cout

很多时候使用 c++ 的输入输出更简单,在应对输入输出量不是很大的题目的时候,我们会采用 cin 和 cout 来提高我们的解题速度。

Example:求两个数之和

#include //输入输出函数的头文件 
using namespace std;

int main(){
   
   int a,b;
   cin >> a >> b;
   cout << a + b;
   
   return 0;
} 

注:平时练习的时候不要排斥混合编程,即 C 与 C++ 混用,然后用 C++ 提交。但是注意:printf 尽量不要和 cout 同时使用,会发生一些不可控的意外。

头文件技巧

cpp 文件中推荐一个万能头文件:

#include 
using namespace std;

注:要看考试的评测机型支不支持,绝大部分都是支持的,当然准备一个完整的头文件还是有必要的,作为备用。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){
    
    return 0;
} 

注:头文件可以多,但是不能少

数组使用技巧

数组除了可以存储数据以外,还可以用来进行标记

例题 01:

image-20200321120529994

【代码实现】

#include //万能头文件 
using namespace std;

int f[105]={0};//注意:尽量将数组开在全局 
int main(){
    int n,x;
    scanf("%d",&n);
    for(int i=0;i0){
            printf("%d %d\n",i,f[i]);
        }
    }
    return 0;
} 

例题 02:

image-20200321134145614

【代码实现】

#include //万能头文件 
using namespace std;

int f[105] = {0};//注意:尽量将数组开在全局 
int p[105] = {0};//p[i]表示有 i个这样的数的最大值是多少 
int main(){
    int n,x;
    scanf("%d",&n);
    for(int i=0;i0){
            printf("%d %d\n",p[i],i);
        }
    }
    return 0;
} 

例题 03:

【题目】二维数组实现存储地图

####
#.##
##@#
####

【代码实现】

#include //万能头文件 
using namespace std;

char mpt[10][10];
int main(){
    for(int i=0;i<4;i++){
        scanf("%s",mpt[i]);
    }
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            printf("%c",mpt[i][j]);
        }
        printf("\n");
    }

    return 0;
} 

复杂度与是否可做

做好审时度势

算法 循环嵌套 时间复杂度 空间复杂度
冒泡排序 两个 for 循环 O(N^2​)

注:空间复杂度一般不会限制,如果遇到了再想办法优化空间。

时限 1 s 情况下的复杂度:

时间复杂度 N 取值(时限 1 s)
O(N) N 最大在 500w 左右
O(NlogN​) N 最大在 20w 左右
O(N^2​) N 最大在 2000 左右
O(N^2logN​) N 最大在 700 左右
O(N^3​) N 最大在 200 左右
O(N^4​) N 最大在 50 左右
O(2^N​) N 最大在 24 左右
O(N!)​ N 最大在 10 左右

注:如果是 2S、3S 对应的乘以 2 和 3 就可以。

C++ STL 的使用

?> C++ 的算法头文件里有很多实用的函数,我们可以直接拿来用。

#include 

排序函数

  • sort()

  • 依次传入三个参数,要排序区间的起点,要排序区间的终点+1,比较函数。比较函数可以不填,则默认为从小到大排序

  • 示例:

  • #include 
    using namespace std;
    
    int a[105];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=0;i

查找函数

  • lower_bound() 函数

  • upper_bound() 函数

  • lower_bound() 和 upper_bound() 都是利用二分查找的方法在一个排好序的数组中进行查找的。

  • 在从小到大的排序数组中:

  • lower_bound(begin,end,num):从数组的 begin 位置到 end-1 位置二分查找第一个大于或等于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin,得到找到数字在数组中的下标

  • upper_bound(begin,end,num):从数组的 begin 位置到 end-1 位置二分查找第一个大于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin,得到找到数字在数组中的下标

  • 重载 lower_bound() 和 upper_bound()

  • lower_bound(begin,end,num,greater< type >()):

  • 从数组的 begin 位置到 end-1 位置二分查找第一个小于或等于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin,得到找到数字在数组中的下标

  • upper_bound(begin,end,num,greater< type >()):

  • 从数组的 begin 位置到 end-1 位置二分查找第一个小于 num 的数字,找到返回该数字的地址,不存在则返回 end。通过返回的地址减去起始地址 begin,得到找到数字在数组中的下标

  • 示例:

  • //查找函数
    #include 
    using namespace std;
    
    int cmp(int a,int b);
    int main(){
        int num[6]={1,2,4,7,15,34};
        sort(num,num+6);//按从小到大排序
        //返回数组中第一个大于或等于被查数的值
      int pos1 = lower_bound(num,num+6,7)-num;
      //返回数组中第一个大于被查数的值
      int pos2 = upper_bound(num,num+6,7)-num;
      cout<())-num;
      //返回数组中第一个小于被查数的值
      int pos4 = upper_bound(num,num+6,7,greater())-num;
      cout<b;
    }
    

优先队列

  • 通过 priority_queue< int >q 来定义一个储存整数的空的 priority_queue。当然 priority_queue 可以存任何类型的数据,比如 priority_queue< string >q 等等。

  • 示例:

  • //#include 
    #include 
    #include 
    using namespace std;
    
    int main(){
        priority_queue q;//定义一个优先队列
      q.push(1);//入队 
      q.push(2);
      q.push(3);
      while(!q.empty()){//判读队列不为空 
          cout << q.top() << endl; //队首元素 
          q.pop();//出队 
      } 
        return 0;
    }
    

C++ 的 STL (标准模板库)是一个非常重要的东西,可以极大的帮助更快速的解决题目

vector

  • 通过 vector< int >v 来定义一个储存整数的空的 vector。当然 vector 可以存任何类型的数据,比如 vector< string >v 等等

  • 示例:

  • //#include 
    #include 
    #include 
    using namespace std;
    
    int main(){
        vector v;//定义一个空的 vector
      for(int i=1;i<=10;i++){
          v.push_back(i*i);//加入到 vector 中 
      } 
      for(int i=0;i
  • Result:

image-20200322201845985

queue

  • 通过 queue< int >q 来定义一个储存整数的空的 queue。当然 queue 可以存任何类型的数据,比如 queue< string >q 等等

  • 示例:

  • #include 
    #include 
    using namespace std;
    int main()
    {
      queue q;//定义一个队列
      q.push(1);
      q.push(2);
      q.push(3);
      while(!q.empty()){//当队列不为空 
          cout << q.front() << endl;//取出队首元素
          q.pop();//出队 
      } 
      
      return 0;
    }
    

stack

  • 通过 stack< int >S 来定义一个全局栈来储存整数的空的 stack。当然 stack 可以存任何类型的数据,比如 stack< string >S 等等。

  • 示例:

  • #include 
    #include 
    using namespace std;
    int main()
    {
      stack s;//定义一个栈 
      s.push(1);
      s.push(10);
      s.push(7);
      while(!s.empty()){//当栈不为空 
          cout << s.top() << endl;//取出栈顶元素
          s.pop();//出栈 
      } 
      
      return 0;
    }
    

map

  • 通过 map< string, int >dict 来定义一个 key:value 映射关系的空的 map。当然 map 可以存任何类型的数据,比如 map< int, int >m 等等

  • 示例:

  • #include 
    #include 
    #include 
    
    using namespace std;
    int main()
    {
      map dict;//定义一个 map
      dict["Tom"] = 1;//定义映射关系
      dict["Jone"] = 2;
      dict["Mary"] = 1;
      if(dict.count("Mary")){//查找 map
          cout << "Mary is in class " << dict["Mary"]; 
      } 
      //使用迭代器遍历map和value
      for(map::iterator it = dict.begin();it != dict.end();++it){
          cout << it->first << " is in class " << it->second << endl;
      } 
      dict.clear();//清空 map 
      return 0;
    }
    

set

  • 通过 set< string >country 来定义一个储存字符串的空的 set。当然 set 可以存任何类型的数据,比如 set< int >s 等等。

  • #include
    #include
    using namespace std;
    int main(){
      set country;//定义一个存放string的集合
      country.insert("China");//插入操作
      country.insert("America");
      country.insert("France");
      set::iterator it;
      //使用迭代器遍历集合元素
      for(it=country.begin();it!=country.end();++it){
          cout<<*it<<" ";
      }
      cout<

多组输入的问题

即循环输入输出结果

【题目描述】输入两个数,输出两个数的和,要求多组输入

【代码实现】

  • Example 01:C 循环读入代码
#include  
using namespace std;
int main(){
    int a,b;
    while(scanf("%d%d",&a,&b)!=EOF){
        printf("%d\n",a+b);
    }
    return 0;
}

!> 不能使用 while(1) 这样死循环,!=EOF 的意思一直读取到文件末尾(Endoffile)另外,多组输入一定要注意初始化问题,数组和变量的初始化要放在 while 循环内,否则上一次的运算的结果会影响当前的结果。

  • Example 02:C++ 循环读入代码
#include  
using namespace std;
int main(){
    int a,b;
    while(cin >> a >> b){
        cout << a + b << endl;
    }
    return 0;
}
  • Example 03:Java 循环读入代码
Scanner stdin = new Scanner(System.in);
while(stdin.hasnext()){
    String s = stdin.next();
    int n = stdin.nextInt();
    double b = stdin.nextDouble();
}
  • Example 04:Python 循环读入代码
while true:
    try:
        a, b = map(int, input().split())
        c = a + b
        print(c)
    except:#读到文件末尾抛出异常结束循环
        break

你可能感兴趣的:(【OJ】机试指南 第一章)