奇迹银桥「2」

上回反响不行啊……

这会Miemeng要给大家三个考试技巧!

1.‘#’系列(预处理器)

#if
#ifdef
#ifndef
#elif
#endif
#undef
#define

 上面这些非常有用!

我们主要说一下 #ifdef 这样的(有用!)

考试时往往要开 freopen 于是有人忘了,有人不习惯文件输入输出

所以用下面的代码片:

#include <bits/stdc++.h>

using namespace std;

int main(){
#ifndef LC   
/*LC 也可以写自己喜欢的变量名*/
    freopen("*.in" ,"r",stdin);
    freopen("*.out","w",stdout);
#endif
/*照常打代码*/
}

 稍稍解释一下:

 #if 就类比于 if ,只是针对编译器起作用,意思就是说后面是 true 就编译下面的语句(不要以为你可以在后面加一个变量)

于是 #endif 是结束这个过程(一个 if 管全局要命啊)

那么 #ifdef  就是另一个版本,意思是说后面的宏(可以理解为一个常量)被定义了,就编译下面的语句

 #ifndef 就是$if not define$,可以理解是上面的取非。

 #elif 就很好理解了吧,就是类似$else \, if$的东西

如果要和 #ifdef 一起用还要写个 #elif defined A (如果上面的未定义却定义了A,就编译下面的语句,否则跳过跳到 #endif )

说这么大一坨其实也没啥用

下面说一个必须要知道的东西:

当你使用了上面的代码片后,$g++$编译,你就会发现它还是文件输入输出(不要打我啊,还没有说完)(别打脸……啊)

因为你并没有定义$LC$所以还是没法跳过 freopen ,

于是用下面的$g++$编译

g++ file.cpp -o file -D LC

后面的 -D LC 非常好理解啊,就是在编译时定义一下$LC$

发现还有一个#undef

与#define 相对

将后面的宏解除定义

#include <iostream>
#define N 123

using namespace std;

int main(){
	cout<<N<<endl;//输出123
#undef N
	cout<<N<<endl;//这里会告诉你N没定义
}

剩下的就是没啥用的了:

#error
#warning
#pragma

 #pragma大家应该都明白是什么……

这里说一个:message("sting")

用法:

#pragma message( "输出一条Note!" )

作用?也许并没有

#error是好东西(虽然没有什么用)

#error 输出一条error,不写引号也可以!

 #warning就不好用了,它只能控制警告的输出QwQ(所以根本没有用)

至于到底怎么用,去$C++$手册

2.文件流 & 字符串流

别以为名字很高大上就很厉害,其实和第一课学的$cin$ $cout$是兄弟

文件流:

调库:

#include <fstream>

 定义:

fstream a,b,c,d;

使用:

首先打开文件:

a.open("文件名",/*参数*/ios_base::in);

 后面的参数有下面几种:

ios_base::in //输入(类比与cin)
ios_base::out //输出 (类比与cout)
ios_base::app//在文件的末尾cout (不新建文件)

 所以给个例子:

#include <bits/stdc++.h>
#define N 101010
using namespace std;

void ran(){
	int l,c,qn;
	fstream rin,rout;
	rin.open("std",ios_base::in);
	rout.open("vegetable.in",ios_base::out);
	rin>>l>>c>>qn;
	rout<<l<<" "<<c<<" "<<qn<<endl;
	for(int i=1;i<=l;i++){
		for(int j=1;j<=c;j++){
			rout<<rand()%100000<<" ";
		}rout<<endl;
	}
	for(int i=1;i<=qn;i++){
		int a=rand()%l+1,b=rand()%c+1,
			c=rand()%l+1,d=rand()%c+1;
		rout<<min(a,c)<<" "<<min(b,d)<<" "<<max(a,c)<<" "<<max(b,d)<<endl;
	}rout<<endl;
}
int main(){
	int T=N;
	srand(time(0));
	//ran();return 0;
	while(T--){
		if(T%10000==0)srand(time(0));
		ran();
		system("time ./ac");
		system("./bl");
		if(system("diff ac.out bl.out")){
			puts("WA");
			return 0;
		}
		cout<<T<<"/"<<N<<"AC"<<endl;
	}
}

 所以研究一番代码,发现这是把ran直接揉到对拍里写的

有什么好处?

  1. 可以把一个随机数时间种子充分利用,比如上面的代码中每个种子中,随机数用了10000次
  2. 可以实时控制对拍进程,发现可以再开一个流输入数据参数,于是可以在一次对拍中随时更改数据范围……

字符串流:

调库:

#include <sstream>

 定义:

stringstream q;

 使用:

就是把一个数输到字符串里,或是从字符串里读出一个数

(没啥用,而且特特特特特特特特特特别慢)

具体例子可以看这个一件建文件的代码(别乱改,容易爆,或者先把死循环打掉)

#include <bits/stdc++.h>
using namespace std;
string p,x;
int main(){
	fstream init;
	init.open("Number.pre",ios_base::in);
	if(init.is_open()){
		init>>p>>x;
	}
	else {
		init.close();
		init.open("Number.pre",ios_base::out);
		init.close();
		init.open("Error",ios_base::out);
		init<<"Need A File Named Number.pre
A *.pre file is for File name"<<endl;
		init.close();
		return 0;
	}
	for(int i=0;;i++){
		stringstream q;
		string k;
		q<<i;
		q>>k;
		k=p+k+x;
		fstream a;
		a.open(k.c_str(),ios_base::in);
		if(a.is_open()){
			a.close();
		}
		else{
			fstream b;
			b.open(k.c_str(),ios_base::out);
			b.close();
			return 0;
		}
	}
}

 3.STL的一点点骗分技巧

mt19937

基于梅森缠绕器算法,可以产生循环节长达$2^{19937}$的随机数(至于梅森缠绕器,我也不知道那是啥)

用法?和 rand() 一样

Upd:mt19937适用于值域在整个实数域的$[-Inf,+Inf]$,因为能产生均匀的正数和负数。

调库:

#include <random>

 使用:

#include <bits/stdc++.h>

using namespace std;
mt19937 ran(time(0));
int main(){
	cout<<ran()<<endl;
}

 好简单啊~~记得开C++11

数据结构(杂)

 vector 可以 reserve 来分配内存防止它倍增到你MLE

#include <bits/stdc++.h>

using namespace std;
vector<int>k;
int main(){
	k.reserve(100);
}

  unordered_map 是基于 hash 的$O(1)$查询map

#include <unordered_map>

using namespace std;
unordered_map<int,int>k;
int main(){
	k.rehash(100);
}

 P.S. 别忘了开C++11


 完结了,累死了……

可能不会再更了(倾出了毕生绝学)

原文地址:https://www.cnblogs.com/kalginamiemeng/p/QJYQ2.html