ACM之奇奇怪怪的知识

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()

  1. cin>>
    用法一:最常用、最基本的用法,输入一个数字
    用法二:接受一个字符串,遇“空格”、“Tab”、“回车”都结束
  2. 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’
  3. getline() 可以用于接收string类字符串,其他的函数都只能接收char类型字符串
    getline(cin,str) //接受一个字符串,可以接收空格并输出,需包含“#include”
  4. gets()
    gets(ch)// 接受一个字符串数组(char),可以接收空格并输出,需包含“#include
  5. 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函数

  1. “去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址。切记,没有排序前只是去掉相邻的重复元素,如果要真正去重就要排序
  2. 由于返回的是容器末尾,所以如果想得到去重后的size,需要减去初始地址,lower_bound是得到地址,稍微不同。
sz = unique(b + 1,b + n + 1)-(b + 1);
sz = unique(a,a + n) - a;

出现RE的几种可能

  1. ACCESS_VIOLATION 您的程序想从一些非法的地址空间读取或向其中写入内容。一般例如指针、数组下标越界都会造成这个错误的。
  2. ARRAY_BOUNDS_EXCEEDED 您的程序试图访问一个超出硬件支持范围的数组单元。
  3. FLOAT_DENORMAL_OPERAND 进行了一个非正常的浮点操作。一般是由于一个非正常的浮点数参与了浮点操作所引起的,比如这个数的浮点格式不正确。
  4. FLOAT_DIVIDE_BY_ZERO 浮点数除法出现除数为零的异常。
  5. FLOAT_OVERFLOW 浮点溢出。要表示的数太大,超出了浮点数的表示范围。
  6. FLOAT_UNDERFLOW 浮点下溢。要表示的数太小,超出了浮点数的表示范围。
  7. INTEGER_DIVIDE_BY_ZERO 在进行整数除法的时候出现了除数为零的异常。
  8. INTEGER_OVERFLOW 整数溢出。要表示的数值太大,超出了整数变量的范围。
  9. 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在这里插入图片描述

只有是斐波那契序列时才会一定构不成三角形,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的自定义排序

  1. map按键值Key排序
  • 默认按照less<key>升序排列

  • 定义map时,用greater< Key>实现按Key值递减插入数据

    multimap<int,int,greater<int> >mp;//注意<int>后空一格
    
  • 当Key值为自定义的类时

    1. 写一个函数对象仿函数

      #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;
      }
      
    2. 在类里重载小于号<,注意只重载小于号,不要去重载大于号如果想改变为 升 / 降序列,只需改变判断条件即可

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+m1n

__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;
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值