ACM-拓展知识点

本文最后更新于:December 3, 2021 pm

记录ACM中一些好用的小技巧、方法,以及一些见的少的知识点及其用法。

1.求负数的绝对值

1
2
3
4
5
方法:取反加1
例:求-125的绝对值
int n=~-125+1; //n=125
int m=-125;
int t=~m+1; //t=125

2.求素数

1
2
3
4
5
6
7
8
分为奇、偶数求。
bool isprime(int n){
if(n%2==0) return false; //2需特判
for(int i=3;i<=sqrt(n);i+=2){ //奇数只能由奇数的积得来,3需要特判
if(n%i==0) return false;
}
return true;
}

3.求2个数的平均数

1
2
3
4
正常求两个数的平均数为相加除以2,但如果是两个很大的数呢?以至于相加的结果超出了所有整数类型的范围?相加的结果超出了数据的最大范围值时。这时为防止这样的两个很大的数相加的结果超出数据类型的最大值。采用新的求法。
int a=100,b=62;
int mid1=(a+b)/2; //常规做法
int mid2=(b-a)/2+a; //技巧算法

4.求2的n次方

1
2
3
4
5
6
int t=1<<n; //2的n次方
补充:
m<<t;//m乘以2的t次方 m*(2^t)
int m=n<<1; //n乘以2
m>>t;//m除以2的t次方 m/(2^t)
int m=n>>1; //n除以2

5.求一个数取余2的n次方后的数

1
2
3
因为2的次方用二进制来表示会成为1000...的形式,所以也可以通过按位与运算来进行取余,因为凡是后面不为0的为对应的都是余数。
n&3;//n取余4
n&((1<<m)-1);//n取余2^m

6.求两个数的最大公约数

1.辗转相除法
a,b不可以为 0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main(){
int a, b, i;
printf("请输入两个整数:\n");
printf("a=");
scanf("%d", &a);
printf("b=");
scanf("%d", &b);
i = a % b;
while(i != 0){
a = b;
b = i;
i = a % b;
}
printf("%d",b);
return 0;
}

2.位运算
a,b不可以为 0。

1
2
3
4
int gcd(int a,int b){
while(b^=a^=b^=a%=b);
return a; //最大公约数
}

3.三目运算
a,b可以为 0。

1
2
3
inline int gcd(int a,int b) {
return b>0 ? gcd(b,a%b):a;
}

4.C++自带函数

1
__gcd(a,b);

7.用scanf输入string

代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <string>
using namespace std;
int main(){
string a;
a.resize(100); //需要预先分配空间
scanf("%s", &a[0]); //不能写成&a,必须要写&a[0]
//printf("%s",a.c_str());
//puts(a.c_str());
cout<<a.c_str()<<endl;
return 0;
}

c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。

7.1从指定的下标开始输入

1
2
3
4
5
6
7
//这里以从下标1开始存入
string s;
s.resize(100);
scanf("%s",&s[1]); //指定从下标1开始存
for(int i=1;i<=10;++i) printf("%c",s[i]);
printf("\n");
printf("%c",s[1]);

8.优先队列(priority_queue)的自定义排序

实现一

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const long long maxn=1e6+5;
#define PI acos(-1)
struct sq{
int num ,id;
};
bool operator<(const sq &x, const sq &y){//重载小于号,适用于优先队列的排序规则
if(x.num==y.num)
return x.id>y.id; //小的数在前面,与其他的容器用法区别开。就同在优先队列中的greater和less用法和在其他容器中greater和less用法相反一样。下同
else
return x.num>y.num;
}
void solve(){
int n;
priority_queue<sq> s;
sq a;
a.id=10;
a.num=30;
s.push(a);
a.id=20;
a.num=40;
s.push(a);
a.id=30;
a.num=50;
s.push(a);
a.id=3;
a.num=50;
s.push(a);
int len=s.size();
cout<<len<<endl;
for(int i=0;i<len;++i){
sq t=s.top();
cout<<t.num<<" "<<t.id<<endl;
s.pop();
}
}
int main(){
IOS;
solve();
return 0;
}
//输出结果
4
30 10
40 20
50 3
50 30

其中,自定义排序规则的方法还有一种:

实现二

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const long long maxn=1e6+5;
#define PI acos(-1)
struct sq{
int num ,id;
bool friend operator<(sq x,sq y){ //解释同上面的
if(x.num==y.num)
return x.id>y.id;
else
return x.num>y.num;
}

};
void solve(){
int n;
priority_queue<sq> s;
sq a;
a.id=10;
a.num=30;
s.push(a);
a.id=20;
a.num=40;
s.push(a);
a.id=30;
a.num=50;
s.push(a);
a.id=3;
a.num=50;
s.push(a);
int len=s.size();
cout<<len<<endl;
for(int i=0;i<len;++i){
sq t=s.top();
cout<<t.num<<" "<<t.id<<endl;
s.pop();
}
}
int main(){
IOS;
solve();
return 0;
}
//输出结果
4
30 10
40 20
50 3
50 30

输出的结果都是一样的。

9.异或的作用

1.对于任何数x,都有x^x=0,x^0=x,同自己求异或为0,同0求异或为自己。
2.结合律(即(a^b)^c == a^(b^c))。
3.自反性 A ^ B ^ B = A ^ 0 = A ,连续和同一个因子做异或运算,最终结果为自己。

9.1找出那个唯一落单的数(其他出现两次,唯独它出现一次)

1
2
int ans=0;
ans^=a[i]; //a为存储所有数的数组。

持续更新中······