一、做题时应注意的地方
1、
做题时考虑输出结果的上、下边际范围,极限值,尤其是在做简单题的时候。
2、
除法能换成乘法的地方,尽量用乘法。
3、
做题时,确保每个句子、每个单词都读懂,读题是做题的根本
4、
处理字符串,千万要保证它以“\0”结尾
5、
进行数组优化,可以在输入的时候就进行向结果靠拢的操作
6、
应用分治处理时
调用函数时,传数组只需打入数组名
传数组内元素如:temp(a[0]);
7、
C语言中大多数头文件在C++中仍然可以用,但推荐在头文件前加一个小写的c字母,然后去掉.h后缀,如ctype.h——cctype
8、
比赛结束前,一定要把正确率稍高点的题都看完
9、
做题时,弄懂题意是前提,普遍最先刷出来的题一定是水题,普遍都做出来的题也一定不难,不要把问题复杂化
10、
注意题目中,测试数据的范围,数组千万别开小了,数据的类型千万别选错了
11、
分治三步法
划分问题:把问题的实例划分成子问题
递归求解:递归解决子题
合并问题:合并子问题的解得到原问题的解
12、
有的题可能用到
scanf("%d,%d",&a,&b);
scanf("%d/%d",&a,&b);
中间必须要输入该字符才可以
13、
浮点数计算有误差,可以用a- dis > 1e-5的形式,
14、
有时题意有说输入时,N>M,但还是比较交换一下确保比较好
15、
对数是处理数论的主要工具
二、零散知识点补漏
1、
^为位运算,表示异或,开关性
如:1010^1111=0101
与(&)、或(|)、非(!)
与集合有关的题可以用位运算:
10110:表示集合{1,2,4}
01100:表示集合{2,3}
位的最后一位为1,表示空集。
全集定义为ALL_BITS=(1<<n)-1
与、或、非,对应集合的交、并、对称差
2、
数组开的很大时,放在main()函数外面
3、
a[x][y]==0;可简写为!a[x][y];
4、
可用如下语句控制空格的输出,第一个输出前没有空格,剩下的输出前都以空格。
for (int i = 0; i < n; i++)
{
if (i != 0) printf(" ");
………………..
}
5、
C++输入带空格的字符串(特别注意,字符串必须用string类型)
举例: #include<iostream>
using namespace std;
int main()
{
string s;
while(getline(cin,s)!=NULL)
{
cout<<s<<endl;
}
return 0;
}
6、
在C语言中,“乘以2”也可以写成“<<1”,意思是“左移一位”。
7、
0、1互换,可应用于标记法
#include<iostream>
usingnamespace std;
int main()
{
int a,q=1;
for(int i=0;i<4;i++)
{
q=!q;
cout<<q<<" ";
}
return 0;
}
输出结果:0 1 0 1
重点:q=!q;
8、
PI=acos(-1.0)
9、
C语言中“%03d”:输出一个数值变量,不足3位前面补0.
10、
不借助变量交换(不推荐用)
int a,b;
scanf("%d%d",&a,&b);
a=a+b;
b=a-b;
a=a-b;
printf("%d%d\n",a,b);
可简化为a^=b^=a^=b;
11、
C语言中输出“%d”字符
用printf("%%d");
puts("%d");
12、
竞赛平台
int范围约为:-2.1*10^9~2.1*10^9
long long范围约为:-9.2*10^18~9.2*10^18
unsigned long long 范围,0~1.8*10^19
注意:定义无符号类型时要加uLL,如:10108uLL;
13、
计算数据类型的范围
#include<limits>
cout<<std::numeric_limits<int>::max()<<endl; //int能表示的最大值
cout<<std::numeric_limits<int>::min()<<endl; //int能表示的最小值
14、
10^-6可编写为1e-6
15、
往数组中输入不定量个数的数
int a[1000],n=0,x;
while(cin>>x)
a[n++]=x;
16、
不限次输入字符
while((c=getchar())!=EOF) //C语言
17、
if(a[i])意思是,如果a[i]==1;
If(!a[i])意思是,如果a[i]==0;
18、
测量string类型长度变量用length(),如:
string t;
inttt=t.length();
19、typedef struct
可用typedef struct{double x,y;}Point;的形式代替结构体,让其更像新生结构类型
20、
string类型的数据相加,就是字符串拼接
21、
定义大数组时尽量用如下形式:
using namespace std;
const int maxn=10000;
int a[maxn];
22、不定长数组:vector
Vercor就是一个不定长数组,例如:若a是一个vector,可以用a.size()读取它的大小,a.resize()改变大小,a.push()_back()向尾部添加元素,a.pop_back()删除最后一个元素,clear()清空,empty()测试是否为空
Vector是一个模板类,用vector<int> a或者vector<double> b来声明一个vector,vector<int>类似于int a[]的整型数组
23、集合:set
set<string>::iterator是迭代器,类似于指针
set迭代器中的元素已从小到大排列好
24、映射:map
就是从键到值得映射,如:
map<string,int> month_name来表示“月份名字到月份编号”的映射,然后用month_name[“July”]=7;来赋值,更多理解详见UVA156
25、数据结构
1.STL的栈在头文件<stack>中,用stack<int> s声明
2.STL的队列在头文件<queue>中,front()取队列首元素,用queue<int> s声明
3.STL的优先队列在<queue>中,优先级高的先出,用priority_queue<int>pq来声明,top()表示优先出队列的元素
5.栈、队列、优先队列都用push()表示入,用pop()表示出。
26、
用优先队列实现一个“个位数大的整数优先级反而小”
用priority_queue<int, vector<int>, cmp >pq的方式定义。下面是cmp的定义:
struct cmp
{
bool operator() (const int a,const int b) const //a的优先级比b小时返回true
{
return a%10>b%10;
}
};
27、
“越小的整数优先级越大到的优先队列”可以写成“ priority_queue<int,vector<int>,greater<int> >pq”
注意:最后的“>”不要写在一起,否则会被认为是“>>”运算符
28、计算一个数转换成二进制中1的个数
#include<iostream>
using namespace std;
{
int count = 0;
while (n) {
count++;
n= n & (n - 1);
}
return count;
}
int main()
{
char n;
while(cin>>n)
cout<<quickOne(n)<<endl;
return 0;
}
*29、麻烦样例的输入
在int main()中输入,并把文件放入程序所在文件夹,检测样例对错
要加有文件#include<cstdio>
30、允许输入空格的字符输入,到数组中
char c;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=5;j++)
{
a[i][j]=getchar();
}
getchar(); //注意:还要有一个getchar()用来放回车符
}
31、多边形的三角剖分公式
即使求:在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。
a[n+1] 4n-6 ------- = ------- a[n] n
a[4]=2,a[5]=5,a[6]=14,a[7]=42
32、文本结束符(:p>)
括号内的,在用freopen("a.txt","r",stdin);该语句的时候,在txt文档中可用到
33、求逆序对数
举例:
#include<iostream>
using namespace std;
long long cnt;
int a[500010];
int T[500010]; //必须定义在前面
void merge_sort(int* A,long long x,longlong y)
{
if(y-x>1)
{
int m=x+(y-x)/2; //划分
int p=x,q=m,i=x;
merge_sort(A,x,m); //递归求解
merge_sort(A,m,y); //递归求解
while(p<m||q<y)
{
if(q>=y||(p<m&&A[p]<=A[q]))
T[i++]=A[p++]; //从左半数组复制到临时空间,比较后小的赋给虚拟空间
else
{
T[i++]=A[q++]; //从左半数组复制到临时空间,比较后大的赋给虚拟空间
cnt+=m-p;
}
}
for(i=x;i<y;i++)
A[i]=T[i]; //从辅助空间复制回A数组
}
}
int main()
{
intn;
while(cin>>n&&n!=0)
{
cnt=0;
for(int i=0;i<n;i++)
cin>>a[i];
merge_sort(a,0,n);
cout<<cnt<<endl;
}
return0;
}
34、求不大于正整数x的与x互质的正整数的个数,
例如phi(1)=1,phi(2)=1,phi(3)=2,phi(4)=2,phi(5)=4,phi(6)=2等等。
unsigned euler(unsigned x)
{ //就是公式
unsignedi, res=x;
for(i = 2; i < (int)sqrt(x * 1.0) + 1; i++)
if(x%i==0){
res= res / i * (i - 1);
while(x % i == 0) x /= i; // 保证i一定是素数
}
if(x > 1) res = res / x * (x - 1);
returnres;
}
35、
可以通过数学运算,确定某个变量的范围
36、部分背包问题思路
有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过C的情况下让总价值尽量高。每个物体都可以之取走一部分,价值和重量按比例计算。
思路:应该综合考虑两个因素。贪心的策略是,优先拿“价值除以重量的值”最大的,直到重量和正好为C判断是否是素数
37、判断是否是素数
int prime(int a)
{
int i;
for(i=2;i<sqrt(a);i++)
if(a%i==0)
return 0;
if(i>sqrt(a))
return 1;
注意:调用时用if(prime(a[i])==1)
38、一个数分解成素数形式
#include<iostream>
using namespace std;
int main()
{
int n,n2;
cin>>n;
n2=n;
cout<<n<<"=";
for(int i=2;i<=n;i++)
{
for(;n2%i==0;)
{
n2=n2/i;
cout<<i<<"*";
}
}
cout<<"1";
return 0;
}
39、把结构体,按某一变量标准快速排序
举例:以e为标准,从小到大排序(整个结构体都以e为标准排序好了)
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct{int s,e;}Time;
bool cmp(Time a,Time b)
{
return a.e<b.e;
}
int main()
{
Time t[10005];
for(int i=0;i<5;i++)
cin>>t[i].s>>t[i].e;
sort(t,t+5,cmp);
for(int i=0;i<5;i++)
cout<<t[i].s<<" ";
cout<<endl;
for(int i=0;i<5;i++)
cout<<t[i].e<<" ";
return 0;
}
40、
贪心算法,只考虑当前状态,让它成为最优
三、杂类
1、子集生成
1、增量构造法
#include <iostream>
using namespace std;
int a[20];
/*递归输出n以内所有的子集,其中cur为当前下标,初始值0*/
void print_subset(int n,int* a,int cur){
for(int i=0;i<cur;i++)//每次递归输出当前子集,靠它来最后输出上一层指定的子集
cout<<a[i]<<' ';
cout<<endl;//以行分隔
//找到当前子集首个值,因为按字典顺序输出,所以每次找到最小的元素,cur>0则minElem=a[cur-1]+1,否则为0
intminElem = cur?a[cur-1]+1:0;
//从子集第一个值开始遍历,先不看下面的print_subset(n,a,cur+1);但看这for循环,
//可知是将子集第一个值从头往后依次赋值为minElem-n-1.每次第一个值变化后递归设置下一个值(相当于下一层的第一个值)
for(int i=minElem;i<n;i++){
a[cur]=i;//当前层子集第一个值
//cur+1表示当前层值设置完毕,开始递归下一层,和前面步骤一样。
//到达最后一层结束后return 到上一层,然后i++,a[cur]的值(首元素)改变,又反复递归下一层...
print_subset(n,a,cur+1);
}
}
int main(){
intn ;
while(cin>>n,n){
print_subset(n,a,0);
}
}
1、位向量法
#include <iostream>
using namespace std;
bool b[20]={0};//判断当前每一个节点选中状态
/*递归输出n以内所有的子集,其中b表示该节点是否选中,cur为当前下标,初始值0*/
void print_subset(int n,bool* b,int cur){
//当cur加到n的时候输出该串节点(解答树)的值
if(cur==n){
for (int i=0;i<n;i++){
if(b[i])
cout<<i<<' ';
}
cout<<endl;
return ;
}
b[cur]=true;//该节点设为选中状态
print_subset(n,b,cur+1);//cur+1递归该状态时的下一层节点,循环该操作
b[cur]=false;//该节点设为不选中状态
print_subset(n,b,cur+1);//cur+1递归该状态时的下一层节点,循环该操作
}
int main(){
intn ;
while(cin>>n,n){
print_subset(n,b,0);
}
}
3、二进制法
#include <iostream>
using namespace std;
int n = 4;
void subset()
{
for(int S = 0; S < (1<<n); S++)
{
cout << "S : " << S << " => ";
for(int i = 0; i < n; i++)
{
if(S & (1<<i))
{
cout << i << "";
}
}
cout << endl;
}
}
int main()
{
subset();
}
2、树状数组求逆序数
举例:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn=500005;
int n;
int aa[maxn]; //离散化后的数组
int c[maxn]; //树状数组
struct Node
{
int v;
int order;
}in[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int t,int value)
{
int i;
for(i=t;i<=n;i+=lowbit(i))
{
c[i]+=value;
}
}
int getsum(int x)
{
int i;
int temp=0;
for(i=x;i>=1;i-=lowbit(i))
{
temp+=c[i];
}
return temp;
}
bool cmp(Node a ,Node b)
{
return a.v<b.v;
}
int main()
{
int i,j;
while(scanf("%d",&n)==1 && n)
{
//离散化
for(i=1;i<=n;i++)
{
scanf("%d",&in[i].v);
in[i].order=i;
}
sort(in+1,in+n+1,cmp);
for(i=1;i<=n;i++) aa[in[i].order]=i;
//树状数组求逆序
memset(c,0,sizeof(c));
long long ans=0;
for(i=1;i<=n;i++)
{
update(aa[i],1);
ans+=i-getsum(aa[i]);
}
cout<<ans<<endl;
}
return 0;
}
四、cmath头文件内函数
math.h 数学函数库,一些数学计算的公式的具体实现是放在math.h里,具体有:
1 、三角函数
doublesin (double);
doublecos (double);
doubletan (double);
2 、反三角函数
doubleasin (double); //结果介于[-PI/2, PI/2]
doubleacos (double); //结果介于[0, PI]
doubleatan (double);//反正切(主值),结果介于[-PI/2,PI/2]
doubleatan2 (double, double); //反正切(整圆值),结果介于
[-PI/2,PI/2]
3 、双曲三角函数
doublesinh (double);
doublecosh (double);
doubletanh (double);
4 、指数与对数
doubleexp (double);
doublepow (double a, double b); //a的b次方
doublesqrt (double);
doublelog (double); //以e为底的对数
double log10 (double);c++ 中自然对数函数:log(N) 以10为底:log10(N)但没有以2为底的函数但是可以用换底公式解决:log2(N)=log10(N)/log10(2)
5 、取整
doubleceil (double); //取上整
doublefloor (double); //取下整
6 、绝对值
doublefabs (double);
7 、准化浮点数
double frexp (doublef, int *p); 标准化浮点数, f = x * 2^p, 已知f
求x, p ( x介于[0.5, 1]) double ldexp (doublex, int p); 与
frexp相反, 已知x,p求f
8 、取整与取余
doublemodf (double,double*);将参数的整数部分通过 指针回传, 返回小数部分
doublefmod(double,double);返回两参数相除的余数
9 、平方根
sqrt
10、计算直角三角形斜边长
用 法:
double hypot(doublex, double y);
举例1:
#include <stdio.h>
#include <math.h>
int main(void)
{
double result;
double x = 3.0;
double y = 4.0;
result = hypot(x, y);
printf("The hypotenuse is: %lf\n",result);
return 0;
}
11、四舍五入
floor(x+0.5); //解释:等于1的区间为[0.5,1.5)
五、cstring头文件内函数(C++字符串函数)
1、strchr函数,查找字符串s中首次出现字符c的位置。
strchr函数原型:extern char *strchr(const char *s,char c);查找字符串s中首次出现字符c的位置。
举例1:
#include<stdio.h>
#include<string.h>
intmain()
{
char a[17];
char *ptr,c='r';
strcpy(a,"This is a string");
ptr=strchr(a,c);
if(ptr)
printf("The character %c is atposition: %s\n",c,ptr);
else
printf("The character was notfound\n");
return 0;
}
输出结果:The character r is at position:ring
2、memset函数,初始化函数
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
函数原型:void*memset(void *s, int ch, size_t n);
*s为数组名,ch为要填充的数,n为选择填充数组的长度(一般用sizeof(数组名))
举例1:填充字符
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a[5];
memset(a,'1',5);
for(int i=0;i<5;i++)
cout<<a[i]<<"";
return 0;
}
输出结果:11111
举例2:填充整数0,只能是0
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int a[5];
memset(a,0,sizeof(a));
for(int i=0;i<5;i++)
cout<<a[i]<<" ";
return 0;
}
输出结果:0 0 0 0 0
3、memmove函数
函数原型:
void *memmove( void* dest, const void* src,size_t count );
功能:
由src所指内存区域复制count个字节到dest所指内存区域,如果src和dest出现重叠,函数会自动处理,返回dest的值。
举例1:将字符串移动
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[]="Golden Global View";
memmove(s,s+7,strlen(s)+1-7);
printf("%s",s);
getchar();
return 0;
}
输出结果:GlobalView
4、memcpy函数
举例1:将s中的字符串复制到字符数组d中
#include<stdio.h>
#include<string.h>
int main()
{
char*s="GoldenGlobalView";
char d[20];
memcpy(d,s,(strlen(s)+1));
printf("%s",d);
getchar();
return 0;
}
输出结果:GoldenGlobalView
举例2:将s中第6个字符开始的6个连续字符复制到d中。(从0开始)
#include<stdio.h>
#include<string.h>
int main()
{
char *s="GoldenGlobalView";
char d[20];
memcpy(d,s+6,6); //从第6个字符(V)开始复制,连续复制6个字符(View)
d[6]='\0';
printf("%s",d);
return 0;
}
输出结果: Global
举例3:复制后覆盖原有部分数据
#include<stdio.h>
#include<string.h>
int main()
{
char src[]="******************************";
char dest[]="abcdefghijlkmnopqrstuvwxyz0123as6";
printf("destinationbeforememcpy:%s\n",dest);
memcpy(dest,src,strlen(src));
printf("destinationaftermemcpy:%s\n",dest);
return 0;
}
输出结果:destinationbefore memcpy:abcdefghijlkmnopqrstuvwxyz0123as6
destination after memcpy: ******************************as6
5、memchr函数,从buf所指内存区域的前count个字节查找字符ch。
函数原型:
extern void *memchr(const void *buf, intch, size_t count);
功能:
从buf所指内存区域的前count个字节查找字符ch。
6、strlen函数(正好是字符串中字符的个数)
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char*s="GoldenGlobalView";
cout<<strlen(s)<<endl;
return 0;
}
输出结果:16
7、strrev函数(翻转字符串)
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char s[]="WelcomeToBeijing";
cout<<strrev(s)<<endl;
return 0;
}
输出结果:nijieBoTemocleW
8、strupr(将字符串s1中小写字母转换为大写)
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char s1[]="abcdef";
char *s2=strupr(s1);
cout<<s2<<endl;
return 0;
}
输出结果:ABCDEF
9、strlwr(将字符串s1中大写字母转换为小写)
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char s1[]="ABCDEF";
char *s2=strlwr(s1);
cout<<s2<<endl;
return 0;
}
输出结果:abcdef
10、strstr(函数搜索一个字符串在另一个字符串中的第一次出现)
举例1:
#include<stdio.h>
#include<string.h>
int main()
{
char*s="GoldenGlobalView";
char*l="lob";
char*p;
p=strstr(s,l);
if(p)
printf("%s",p);
else
printf("NotFound!");
return 0;
}
输出结果:lobalView
11、strcat函数,字符串剪接(把src所指字符串添加到dest结尾处)
函数原型:
extern char *strcat(char *dest,char*src);
功能:
把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char d[20]="GoldenGlobal";
char s[20]="View";
strcat(d,s);
cout<<d<<endl;
return 0;
}
输出结果:GoldenGlobalView
12、strncat函数,剪接n个字符(把src所指字符串的前n个字符添加)
函数原型:
extern char *strncat(char *dest,char*src,int n);
功能:
把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处
的'\0')并添加'\0'。
举例1:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char d[20]="GoldenGlobal";
char *s="ViewWinIDELibrary";
strncat(d,s,5);
cout<<d<<endl;
return 0;
}
输出结果:GoldenGlobalViewW
13、strcpy函数,字符串复制
函数声明:
extern char *strcpy(char* dest, constchar *src);
功能:
把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间