OI易错点-C++语法
不保证本文内容完全正确,仅仅是个人总结!!
islower
,isalpha
,isdigit
这种函数,返回值不是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
.find('a')
返回第一次出现a
的位置.find(str_1)
就是找存不存在子串str_1
.find(str_1,pos)
找pos
起str_1
的位置.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)
返回的值是反正切的值
其实就是说,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}$ 时什么都不做
double
占8字节,long double
占16字节,
cmp最好不要写在结构体里,
因为成员函数指针和普通函数指针不同,前者实际上是这样子的。
bool cmp(node*this, int a, int b)
开三次根号的方法(不要用pow
)
cbrt()
答案为double
,可以放long long
进去牛顿迭代法
二分。
笛卡尔树是一种二叉树。
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
)
map
和set
内部的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
,只需要在函数名后面加上 l
或 ll
就可以了,比如 __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
~
包括符号位,按补码取反。
注意 vector
的 insert
是 $\mathcal{O}(n)$ 的。
distance(first,last)
返回两个迭代器的距离
first
和 last
的迭代器类型,直接决定了 distance()
函数底层的实现机制:
- 当
first
和last
为随机访问迭代器时,distance()
底层直接采用last - first
求得[first, last)
范围内包含元素的个数,时间复杂度为 $\mathcal{O}(1)$ 。 - 当
first
和last
为非随机访问迭代器时,distance()
底层通过不断执行++first
(或者first++
)直到first==last
,由此来获取[first, last)
范围内包含元素的个数,时间复杂度为 $\mathcal{O}(n)$ 。
bitset用来存储二进制数位。像一个bool类型的数组一样,bitset每个元素只有0或1两个数值。
但是有空间优化——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]
直接访问!!