嘘~ 正在从服务器偷取页面 . . .

OI易错点-C++语法


OI易错点-C++语法

不保证本文内容完全正确,仅仅是个人总结!!

islowerisalphaisdigit 这种函数,返回值不是bool!!

在不同的机器上跑出来是不一样的!!!!不要直接加上它!!!

lower_bound(begin,end,x,greater<int>()) 返回第一个小于等于 \(x\) 的位置

去重 m=unique(b+1,b+1+n)-b-1;

string==find()\(O(n)\) 的!

注意 char 数组后面有个 \0因此多测一般不用清空但是\0后面的不会被清空

next_permutation(a+1,a+1+n)下一个排列!到了5 4 3 2 1这种就结束了!!

同理有 prev_permutation(a+1,a+1+n)

凡是位运算都加个括号,比如 \(\&\) 的优先级比 == 还要低!!!(待考证)

判断两数的奇偶性是否相同不可以用异或因为高位还有数

__gnu_pbds的头文件可以用 #include <bits/extc++.h>

memcpy(a,b,sizeof(b)) 把 b 复制到 a

char s[]={'a','b','c','\0','d','c'};
char t[]="12";
signed main()
{
    cout << s << '\n'; // 输出:abc
    printf("%s\n",s); // 输出:abc
    memcpy(s,t,2); // 把 t 的前 2 个字符复制给 s
    cout << s << '\n'; // 输出:12c
    printf("%s\n",s); // 输出:12c
    for(int i=0; i<6; i++) printf("%c",s[i]); // 输出:12cdc
    cout << '\n';
    memcpy(s,t,3); // 把 t 的前 3 个字符复制给 s
    cout << s << '\n'; // 输出:12
    return 0;
}

自定义优先队列

struct cmp
{
    bool operator()(int a,int b)
    	{return h[a]<h[b];}
};
priority_queue<int,vector<int>,cmp> q; // 每次返回h最大的那个

str.c_str() 可以把string转化为char[] ,然后printf("%s\n",res.c_str());

string str

  1. .find('a')返回第一次出现a的位置
  2. .find(str_1)就是找存不存在子串 str_1
  3. .find(str_1,pos)posstr_1 的位置
  4. .substr(begin,length) 返回原串长度为 length 的前缀

string::find(str,pos),没找到返回的是 18446744073709551615 ,即string::npos

char 数组比较用 strcmp(<a>,<b>)不要直接用 ==会出问题

reverse 函数 [first,last) ,其他比如 sort 也是类似。


fixed表示定点数

  • 如果不用fixed直接用setprecision(x)就是最多有效位数为 \(x\) ,而且是科学计数法+四舍五入
  • 如果用了fixed 那么setprecision(x) 就是小数点后最多位数 \(x\) ,非科学计数法+四舍五入


atan2(y,x) 返回的值是方位角(极角)的值

atan(y,x) 返回的值是反正切的值 \[ \begin{aligned} \operatorname{atan2}(y,x)= \begin{cases} \arctan(\frac{y}{x})&x>0\\ \arctan(\frac{y}{x})+\pi&y\ge0,x<0\\ \arctan(\frac{y}{x})-\pi&y<0,x<0\\ +\frac{\pi}{2}&y>0,x=0\\ -\frac{\pi}{2}&y<0,x=0\\ \text{undefined}&y=0,x=0 \end{cases} \end{aligned} \]

其实就是说,atan2(y,x)

在一、二象限的时候返回的是 \([0,\pi]\) 的值

在三、四象限的时候,返回的是 \((-\pi,0]\) 的值

atan(y,x) 的返回值只有 \(\left[-\dfrac{\pi}{2},\dfrac{\pi}{2}\right]\)


scanf(“%lf%lf”,&x,&y) 读double

-0x3f3f3f3f3f3f3f3f-1 = (long long)0xc0c0c0c0c0c0c0c0
注意后面一个数本质是 unsigned long long 的,要转成 long long !!!!

合并两端有序的序列(归并的中间步骤)inplace_merge(l,mid,r)

这里的 mid归并时右边一段的开头元素的位置!!

还有 r最右边的元素的右边一个位置!!

如果答案是 -1e-10 这种答案,要注意直接赋值为 0 ,不然会输出 -0.0000

POJ上提交不能用万能头,而且要用 printf + %f 来输出 double

shuffle(p+1,p+1+n,rd); 不用 rd()

#define sum(x) ((x)*((x)+1)/2) 注意宏定义一定要所有的 \(x\) 都套个括号

%llu 输出unsigned long long

getline(cin,str[pos]);

set::count 同 map,都是 \(O(\log n)\)

scanf("%s",a);n=strlen(a+1)

注意左移运算符

如果写1<<31ll(long long)(1<<31)会爆int

要写成1ll<<31

判断第 \(i\) 位是否为\(1\)

((m&(1ll<<(i-1)))!=0) // 一定要写 !=0 而且要套括号!
((m>>(i-1))&1) // 这个安全一点

fread快读不要和 scanf(“%s”,a+1) 这种混用!

assert(x),当 \(x\)\(\texttt{true}\) 时什么都不做

double8字节long double16字节


cmp最好不要写在结构体里,

因为成员函数指针和普通函数指针不同,前者实际上是这样子的。

bool cmp(node*this, int a, int b) 


开三次根号的方法(不要用pow

  1. cbrt() 答案为double,可以放long long进去

  2. 牛顿迭代法 \[ x_{i+1}=x_i-\dfrac{f(x_i)}{f^{\prime}(x_i)} \]

  3. 二分。

笛卡尔树是一种二叉树

stoi()stoll()

对于

bool operator<(node x,node y){return sum[x.id]>sum[y.id];}
priority_queue<node> q;

这样的重载,sum的值一定要在push前就设置好!!!!

nth_element()时间复杂度是 \(O(n)\) 的。(Roundgod说了)

int (*h)[N]可以传二维数组(第二维为 N

mapset内部的find函数查找时间复杂度是 \(O(\log n)\)

unordered_map 查找是 \(O(1)\) 的(除非被卡)


能用int的就不要用double,惨痛教训!!

int f(int x) {return (int)((log(x) / log(10.0)) + 1);}
int g(int x)
{
    int ret=0;
    while(x) x/=10, ++ret;
    return ret;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cout << fixed << setprecision(30);
    cout << (log(1000) / log(10)) + 1 << '\n';
    cout << (int)(log(1000) / log(10)) + 1 << '\n';
    cout << floor(log(1000) / log(10)) + 1 << '\n';
    cout << f(1000) << '\n';
    for(int i=1; i<=100000; i++)
        if(f(i) != g(i)) return cout << i,0;
    return 0;
}

输出为

3.999999999999999555910790149937
3
3.000000000000000000000000000000
3
1000

原因就在double的精度上。


for (n = i = 1; i <= R; ++i, ++n)
    for (j = 1; j < C; ++j, ++n)
        scanf("%d", &w), addedge(n, n + 1, w);
for (n = i = 1; i < R; ++i)
    for (j = 1; j <= C; ++j, ++n)
        scanf("%d", &w), addedge(n, n + C, w);

可以用这个来建网格图(主要是 \(t\) 那个变量的用法)(P3350)

__builtin_popcount

// 返回n的二进制表示形式中1的个数
int __builtin_popcount(unsigned int n)

__builtin_ffs

// 返回n的二进制表示形式中最后一位1的是从后向前第几位
int __builtin_ffs(unsigned int n)

__builtin_clz

// 返回n的二进制表示形式中前导0的个数
int __builtin_clz(unsigned int n)

__builtin_ctz

// 返回n的二进制表示形式中结尾0的个数
int __builtin_ctz(unsigned int n)

__builtin_parity

// 返回n的奇偶校验位,即n的二进制表示形式中的1的个数模2的结果
int __builtin_parity(unsigned int n)

上述列举的这些函数参数都是 unsigned int 类型,如果参数为 usigned long 或者 usigned long long,只需要在函数名后面加上 lll 就可以了,比如 __builtin_popcountl

遗憾的是,这些 builtin 函数一般没有可移植性,使用时要注意。

#define int long long
struct qwq
{
    int num,_;
    qwq operator++(signed) // 只能放int,不能放long long,不知道为什么
    { qwq tmp=*this; ++num; return tmp; } // 重载 b++
    qwq operator++() { num++; return *this; } // 重载 ++b;
} b;


b={0,0};
cout << b++.num << '\n'; // 输出0
cout << ++b.num << '\n'; // 输出2

sqrt()ceil()floor() 返回的是 double 等类型,没有 int

a|b 会把符号位也给 \(\mathtt{or}\) 上。

对负数右移(显然是signed),高位补1

对正数右移,高位补0,没什么问题。

100011 >> 3 (二进制补码,显然这是个负数)-> 111100

~ 包括符号位,按补码取反。

注意 vectorinsert\(\mathcal{O}(n)\) 的。

distance(first,last) 返回两个迭代器的距离


firstlast 的迭代器类型,直接决定了 distance() 函数底层的实现机制:

  • firstlast 为随机访问迭代器时,distance() 底层直接采用 last - first 求得 [first, last) 范围内包含元素的个数,时间复杂度为 \(\mathcal{O}(1)\)
  • firstlast 为非随机访问迭代器时,distance() 底层通过不断执行 ++first(或者 first++)直到 first==last,由此来获取 [first, last) 范围内包含元素的个数,时间复杂度为 \(\mathcal{O}(n)\)


bitset用来存储二进制数位。像一个bool类型的数组一样,bitset每个元素只有01两个数值。
但是有空间优化——bitset中的一个元素一般只占1 bit。
bitset中的每个元素都能单独被访问,例如下面的代码:

输出格式
printf("%d\n",x.to_ulong());
cout<<x<<'\n';

bitset<15>a,b(string("101")); //定义bitset,15是指有15位
a[10]=1;  //将第10位定义为1
输出a;
输出b;
a=101; //赋值a
输出a;

输出:
1024
000010000000000
5
000000000000101
101
000000001100101

可以看出,a[10]=1相当于+2^10。
而下面直接输出bitset就很玄妙。
另外,字符串可以直接转到bitset中。
有意思的是,bitset可以直接赋值!
当然也可以bitset<15>c(101)来赋值!

then

bitset<4> a ( string("1001"));
bitset<4> b ( string("0011"));

cout << (a^=b) << '\n';       // 1010 
cout << (a&=b) << '\n';       // 0010
cout << (a|=b) << '\n';       // 0011 

cout << '\n' << a << '\n';    // 0011
cout << b << '\n' << '\n';    // 0011

cout << (a<<=2) << '\n';      // 1100 
cout << (a>>=1) << '\n';      // 0110

cout << '\n' << a << '\n';    // 0110
cout << b << '\n' << '\n';    // 0011

cout << (~b) << '\n';         // 1100 
cout << (b<<1) << '\n';       // 0110 
cout << (b>>1) << '\n';       // 0001

cout << (a==b) << '\n';       // false (0110==0011)
cout << (a!=b) << '\n';       // true  (0110!=0011)

cout << (a&b) << '\n';        // 0010
cout << (a|b) << '\n';        // 0111
cout << (a^b) << '\n';        // 0101

看完这些,估计您已经对bitset有个深刻的了解,它资瓷位运算!

then

对于一个叫做a的bitset:
a.size()      返回大小(位数)
a.count()     返回1的个数
a.any()       返回是否有1
a.none()      返回是否没有1
a.set()       全都变成1
a.set(p)      将第p+1位变成1
a.set(p, x)   将第p+1位变成x
a.reset()     全都变成0
a.reset(p)    将第p+1位变成0
a.flip()      全都取反
a.flip(p)     将第p+1位取反
a.to_ulong()  返回它转换为unsigned long的结果,如果超出范围则报错
a.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
a.to_string() 返回它转换为string的结果
    
// 来自 https://www.luogu.com.cn/blog/da32s1da/solution-p2114

unique(begin,end) 要减去 begin 才是去重后的数量!这个和其他的实现不太一样。

#define int long long
int _;
mt19937 rd(time(0) + (unsigned int)&_);
cout << l + (int)((double)rd() / UINT_MAX * (r-l+1)) << '\n'; // 生成[l,r]间的随机数

判断一个数是不是平方数:

bool check(int x) { int t = sqrt(x + 0.5); return t * t == x; }

其中 \(0.5\) 是为了防止浮点误差!!!很重要!!!


注意要全部输入数据,不要中间来了个特判直接退出了函数:

cin >> n >> m;
int res = 0; memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++) {
    cin >> a[i]; tmp[i] = a[i]; f[1][i] = 1;
}
if(m == 1) { cout << n << '\n'; return; } // 老生常谈了属于。


unordered_map 和 map 的 [] 操作,在访问不存在元素时会自动创建一个新元素

因此需要使用 mp.count(x) 来判断有没有 x 这个元素,而非 mp[x] 直接访问!!


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录