scanf的返回值是成功输入的参数个数
如scanf(“%d”,&a)成功的话会返回1
scanf(“%d%d”,&a,&b)成功的话返回2
如果遇到错误或遇到end of file,返回值为EOF
当输入数据达到1e6时要用scanf,若用cin会超时
cout<<ends;和cout<<" “;看似都是输出空格,其实不是一样的;
ends实际上是输出了一个’\0’字符,并不是我们想象的空格。
windows和linux对’\0’的处理方式不同,在windows中会输出一个空格,而linux下则不会有什么输出。
因此,输出空格时最好用cout<<” ";
C++中常见的几种输入字符串的方法如下:
cin、cin.get()、cin.getline()、getline()、gets()、getchar()
- cin>>
用法一:最常用、最基本的用法,输入一个数字
用法二:接受一个字符串,遇“空格”、“Tab”、“回车”都结束 - cin.get()
用法一:cin.get(字符变量名)可以用来接收字符
ch=cin.get(); cin.get(ch);
用法二:cin.get(字符数组名,接收字符数)用来接收一行字符串,可以接收空格
cin.get(ch,20);
用法三:cin.get(无参数)没有参数主要是用于舍弃输入流中的不需要的字符,或者舍弃回车,弥补cin.get(字符数组名,接收字符数目)的不足.
3.cin.getline()
cin.getline(ch,20) // 接受一个字符串,可以接收空格并输出
cin.getline()实际上有三个参数,cin.getline(接受字符串数组,接受个数,结束字符)当第三个参数省略时,系统默认为’\0’ 是‘\n’ - getline() 可以用于接收string类字符串,其他的函数都只能接收char类型字符串
getline(cin,str) //接受一个字符串,可以接收空格并输出,需包含“#include” - gets()
gets(ch)// 接受一个字符串数组(char),可以接收空格并输出,需包含“#include - getchar()
getchar()//接受一个字符,需包含“#include
round() 用于对一个具体的数值进行四舍五入,但并不改变这个数
a * b / gcd(a, b) 就是最小公倍数
gcd(a,b)={b?gcd(b,a%b):a;}
long long最大算20的阶乘
int最大算16的阶乘
map可以开数组,mp[i][j]=m
2^k=1<<k
循环遍历:auto
for(atuo c: arr)
注意点:
1.用auto声明的变量必须初始化(auto是根据后面的值来推测这个变量的类型,如果后面没有值,自然会报错)
2.函数和模板参数不能被声明为auto(原因同上)
3.因为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid
4.定义在一个auto序列的变量必须始终推导成同一类型
double类型不能直接进行等量判断,标准做法应该要加一个eps=1e^-6。
const double eps = 1e-6//一般负六次就够了
int e = 10;
if(a+eps<10)//…
if(a<10-eps)//…
if(fabs(a-b)<eps)//判断相等
memset(f,127,sizeof(f));//double无穷大赋值方式
计数类问题:1.DP 2.组合 3.枚举
博弈类问题:1.纯思维 2.找板子 3.搞SG函数
map的最大容量为2^30=1e9;
一个大于5的素数一定在6的倍数周围
accumulate函数:
求和时,accumulate带有三个形参:累加的元素起始地址;累加的元素结束地址,累加的初值(通常为0)。例如:
sum= accumulate(list, list+10, 0) ;
求连乘积时,accumulate带有四个形参:连乘的元素起始地址;连乘的元素结束地址,连乘的初值(通常为1)。例如:
con_product= accumulate(list, list+3, 1, multiplies()) ;
如果要换行的话用puts(“”);最快
printf不能直接输出string类型,printf(“%s” , s.c_str());//string中c_str()成员方法返回当前字符串的首字符地址
arcsin用asin
arccos用acos
arctan用atan
数字转换为字符串(itoa函数)
itoa(i ,num ,10 );
i ---- 需要转换成字符串的数字
num ---- 转换后保存字符串的变量
10 ---- 转换数字的基数(即进制)。10就是说按10进制转换数字。还可以是2,8,16等等你喜欢的进制类型
返回值:指向num这个字符串的指针
itoa 并不是一个标准的C函数,它是Windows特有的,如果要写跨平台的程序,请用sprintf。
标准库中有sprintf,功能比这个更强,用法跟printf类似:
char str[255];
sprintf(str, “%x”, 100); //将100转为16进制表示的字符串。
用memset函数给数组赋值时,只能赋0或-1。
memset(arr,0xff,sizeof(arr));//初始值为-1
若想赋其他的值可以用fill函数,fill(首地址,尾地址,赋的初值);
fill()函数的用法:
1.对一维数组a[n]的赋值,
fill(a,a+n,1)
第一个参数是起始地址
第二个参数是我们需要结束的地方,但不会报告a[n],区间为[a[0],a[n])前闭后开
第三个参数是我们需要的赋值,这个相对memeset()就灵活很多
2.对二维数组a[m][n]的赋值
fill(a[0],a[0]+mn,1)
参数的类型和上面的一样,这里唯一值得注意的是第一个起始地址,因为是二维数组,它的第一个数值的表达是 a[0][0],而它的地址就可以用a[0] 来表示。
例如赋予字符型
const char c=’.’;
fill(a[0],a[0]+1010,c);
vector中查找元素:
int temp1[]={ 1,3,2,4,5,0 };
vector<int> temp(temp1,temp1+6);
vector<int>::iterator it=find(temp.begin(),temp.end(),3);///返回的是地址
int index=&*it-&temp[0];///放入迭代器中得到容器中的位置
printf(“%d\n”,index);
c++中vector find使用:
vector<int>::iterator it = find(vec.begin(), vec.end(), 6);
dilworth定理:
下降子序列的最小划分(最长下降子序列的个数)等于最长不下降子序列的长度
内存限制:256MB
int nums[67108864] 为最大;
long long int nums[33554432]为最大;
C++ sort()从大到小排序参数:greater(),从小到大:less();
sort(a+1,a+1+n,[](ll x,ll y){return x>y;});
数据范围:
short 1e^4
int 2e^9
unsigned int 4e^9
long long 9e^18
unsigned long long 1e^19
__int128 1e^38 (输入输出需要自写快读快输函数,不能用cin,scanf)
对数函数log()用法:
log(真数(幂)):以e为底的对数函数 即ln,如ln x = log(x)
log10():以10为底的对数函数
如果要求自定义以a为底,求log n 的值,则需要使用换底公式即
log an = log(n) / log(a)
一般的,求解的个数用深搜,求最优解用广搜。
find函数:
map,set若未找到则返回end()位,用法map.find(value),vector若未找到则返回-1,用法find(v.begin(),v.end(),value);
c++中string类中的find函数用于寻找字符串中是否包含子串,如果包含,那么函数返回第一个找到的子串的位置,如果不包含,返回-1.
位运算性质:
a|b-a&b=a^b
a|b+a&b=a+b
map和set里面都有内置的lower_bound和upper_bound函数,且比stl里面的快。返回值为迭代器。
unique函数
- “去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址。切记,没有排序前只是去掉相邻的重复元素,如果要真正去重就要排序
- 由于返回的是容器末尾,所以如果想得到去重后的size,需要减去初始地址,lower_bound是得到地址,稍微不同。
sz = unique(b + 1,b + n + 1)-(b + 1);
sz = unique(a,a + n) - a;
出现RE的几种可能
- ACCESS_VIOLATION 您的程序想从一些非法的地址空间读取或向其中写入内容。一般例如指针、数组下标越界都会造成这个错误的。
- ARRAY_BOUNDS_EXCEEDED 您的程序试图访问一个超出硬件支持范围的数组单元。
- FLOAT_DENORMAL_OPERAND 进行了一个非正常的浮点操作。一般是由于一个非正常的浮点数参与了浮点操作所引起的,比如这个数的浮点格式不正确。
- FLOAT_DIVIDE_BY_ZERO 浮点数除法出现除数为零的异常。
- FLOAT_OVERFLOW 浮点溢出。要表示的数太大,超出了浮点数的表示范围。
- FLOAT_UNDERFLOW 浮点下溢。要表示的数太小,超出了浮点数的表示范围。
- INTEGER_DIVIDE_BY_ZERO 在进行整数除法的时候出现了除数为零的异常。
- INTEGER_OVERFLOW 整数溢出。要表示的数值太大,超出了整数变量的范围。
- STACK_OVERFLOW 栈溢出。一般是由于无限递归或者在函数里使用了太大的数组变量的原因。
编译错误:invalid types ‘int[int]‘ for array subscrip
1、数组变量名不一致,或者没定义,比如你定义了一个ans数组,但是你在用的时候误写成了a数组(oj应该爆CE)
2、数组空间不够,比如你要访问a[6],可是你只定义了int a[6]数组,所以下标最多到5,定义改成7就行了。(oj应该爆RE)
3、变量名和数组名重复定义,比如定义了一个int a;然后又定义了一个int a[6];数组,(oj应该爆CE吧)4、定义了一维数组,而使用的时候当用二维数组用
【C/C++】 stdin对字符输入的心得和经验总结(快速输入字符串)
n+n/2+n/3+…+n/n=nlogn![在这里插入图片描述](https://img-blog.csdnimg.cn/08b59b23a591451da2fed0f6b0a111e4.png#pic_center)
只有是斐波那契序列时才会一定构不成三角形,1e9以内的斐波那契序列长度为44
优先队列自定义排序
struct cmp{
bool operator () (type a, type b){
return a < b; // 队头最大;
// return a > b; // 队头最小;
}
};
ceil(a/b)=(a+b-1)/b=(a-1)/b+1;
ceil(a/b)=(a+b-1)/b=(a-1)/b+1
ACM中时间复杂度与时间限制关系
在竞赛中,一般算机一秒能运行5 x 108次汁算,如果题目給出的时间限制カ1s,那么你选择的算法执行的汁算次数最多应该在10^8量级オ有可能解决这个题目。一般 O(n)的算法能解决的数据范围在n < 108。
O(n *logn)的算法能解决的数据范围在n <= 10^6。
O(n*sqrt(n) )的算法能解决的数据范围在n < 10^5。
O(n2)的算法能解决的数据范围在n<5000。
O(n3)的算法能解决的数据范围在n <300。
O(2n)的算法能解决的数据范围在n < 25。
O(n!)的算法能解决的数据范围在n < 11。
以上范围仅供参考,实际中还要考虑每种算法的常数。
C++ STL map的自定义排序
- map按键值Key排序
-
默认按照
less<key>
升序排列 -
定义map时,用greater< Key>实现按Key值递减插入数据
multimap<int,int,greater<int> >mp;//注意<int>后空一格
-
当Key值为自定义的类时
-
写一个函数对象仿函数
#include<iostream> #include<map> using namespace std; typedef struct tagIntPlus { int num,i; }IntPlus; //自定义比较规则 //注意operator是(),不是< struct Cmp { bool operator () (IntPlus const &a,IntPlus const &b)const { if(a.num!=b.num) return a.num<b.num; else return a.i<b.i; } }; int main() { srand((unsigned)time(NULL)); //注意此处一定要有Cmp,否则无法排序会报错 multimap<IntPlus,int,Cmp>mp; int n; cin>>n; int a,b; IntPlus intplus; for(int i=0; i<n; i++) { a=rand()%4; b=rand()%4; intplus.num=a; intplus.i=b; mp.insert(pair<IntPlus,int>(intplus,i)); } map<IntPlus,int>::iterator iter; for(iter=mp.begin(); iter!=mp.end(); iter++) cout<<iter->first.num<<" "<<iter->first.i<<" "<<iter->second<<endl; return 0; }
-
在类里重载小于号<,注意只重载小于号,不要去重载大于号如果想改变为 升 / 降序列,只需改变判断条件即可
-
typedef struct tagIntPlus
{
int num,i;
bool operator < (tagIntPlus const& intplus)const
{
//当num不等时
//前一个对象的num>后一个时返回true,降序排列。
//反之升序排列
if(num!=intplus.num)
return num>intplus.num;
//当num相等时
//前一个对象的i<后一个时返回true,升序排列
else return i<intplus.i;
}
}IntPlus;
multimap<IntPlus,int>mp;//主函数只需将第一种方法中的map中的Cmp去掉即可
2.map按值Value排序
再次强调不能用sort
只能将map中数据压入能用sort的容器,如vector
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>//sort
using namespace std;
typedef struct tagIntPlus
{
int num,i;
} IntPlus;
typedef pair<tagIntPlus,int> PAIR;
//必须有Cmp。
//虽然之后会sort,map的排序并不重要,
//但是map输入数据时需要比较Key值,没有会报错
struct Cmp
{
bool operator () (IntPlus const &a,IntPlus const &b)const
{
if(a.num!=b.num)
return a.num<b.num;
else return a.i<b.i;
}
};
//map会按键值Key升序排列,Value值无要求
//下面才是重点:
bool cmp(PAIR const&a,PAIR const&b)
{
if(a.first.num!=b.first.num)
return a.first.num<b.first.num;
else
{
if(a.first.i!=b.first.i)
return a.first.i<b.first.i;
else return a.second>b.second;
}
}
//上面需重新定义Key升序排列,否则sort之后仅按Value降序排列,Key值被打乱。
int main()
{
srand((unsigned)time(NULL));
multimap<IntPlus,int,Cmp>mp;
int n;
cin>>n;
int a,b;
IntPlus intplus;
for(int i=0; i<n; i++)
{
a=rand()%4;
b=rand()%4;
intplus.num=a;
intplus.i=b;
mp.insert(pair<IntPlus,int>(intplus,i));
}
map<IntPlus,int>::iterator iter;
cout<<"排序前:"<<endl;
for(iter=mp.begin(); iter!=mp.end(); iter++)
cout<<iter->first.num<<"|"<<iter->first.i<<"|"<<iter->second<<endl;
cout<<"排序后:"<<endl;
vector<PAIR>vec(mp.begin(),mp.end());
sort(vec.begin(),vec.end(),cmp);
int size=vec.size();
for(int i=0;i<size;i++)
cout<<vec[i].first.num<<"|"<<vec[i].first.i<<"|"<<vec[i].second<<endl;
return 0;
}
vector<int>vec(mp.begin(),mp.end());
n个球放入m个盒子内,共有多少种放法?(同一盒子内球的个数不同即为不同的放法)
答案: C n + m − 1 n C_{n+m-1}^n Cn+m−1n
__builtin_popcount()
统计数字在二进制中1的个数
容斥原理
当数据范围不大时,可以直接对1—m内的数据标记(前缀和在判断数是否出现时有妙用):
首先开一个 cnt[] 数组记录每个数出现的个数,然后对 cnt 数组进行前缀和
如果sum[1] == sum[10] 说明在[2,10]区间内没有数,两者才会相等
c++按空格分割string的两种方法
string str = "hhh ttt ggg jjj";
//方法一: strtok
char* s = new char[str.size() + 1];
strcpy(s, str.c_str());
char* p = strtok(s, " ");
vector<string> words;
while(p) {
words.push_back(p);
p = strtok(NULL, " ");
}
//方法二: istringstream
istringstream ss(str);
vector<string> words;
string word;
while(ss >> word) {
words.push_back(word);
}
//输出
for(string x : words) {
cout << x << endl;
}