lowbit
非负整数n在二进制表示的形式,最低为的1和以及最低位1后的所有0组成的数
lowbit(n) = n & (-n)
快速幂
typedef long long LL;
int qmi(int a, int k, int p) // 求a^k mod p
{
//这一步不能少
a %= p;
int res = 1 % p;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
约数之和(acwing 97)
题意: 求
A
B
A^B
AB的所有约数之和
分析:
A
可
以
分
解
质
因
数
变
成
a
1
b
1
∗
a
2
b
2
∗
.
.
.
∗
a
n
b
n
A可以分解质因数变成a_{1}^{b1} * a_{2}^{b2} * ...* a_{n}^{bn}
A可以分解质因数变成a1b1∗a2b2∗...∗anbn,
则
A
B
分
解
质
因
数
可
以
变
成
a
1
B
∗
b
1
∗
a
2
B
∗
b
2
∗
.
.
.
∗
a
n
B
∗
b
n
则A^B分解质因数可以变成a_{1}^{B * b1}* a_{2}^{B * b2}*...*a_{n}^{B * bn}
则AB分解质因数可以变成a1B∗b1∗a2B∗b2∗...∗anB∗bn;
因
为
a
1
,
.
.
.
,
a
n
是
A
B
的
约
数
,
所
以
a
1
b
1
∗
.
.
.
∗
a
n
b
n
也
是
A
B
的
约
数
因为a_{1},...,a_{n}是A^B的约数,所以a_{1}^{b1}*...*a_{n}^{bn}也是A^B的约数
因为a1,...,an是AB的约数,所以a1b1∗...∗anbn也是AB的约数;
a
1
b
1
的
取
法
有
b
1
+
1
种
,
例
如
a
1
0
,
a
1
1
,
.
.
.
,
a
1
b
1
a_1^{b1}的取法有b1 + 1种,例如a_1^0,a_1^1,...,a_1^{b1}
a1b1的取法有b1+1种,例如a10,a11,...,a1b1;
因
此
总
的
约
数
个
数
之
和
为
(
b
1
+
1
)
∗
(
b
2
+
1
)
∗
.
.
.
∗
(
b
n
+
1
)
因此总的约数个数之和为(b1+ 1)*(b2 + 1)*...*(bn+1)
因此总的约数个数之和为(b1+1)∗(b2+1)∗...∗(bn+1);
总
的
约
数
之
和
为
(
a
1
0
+
a
1
1
+
.
.
.
+
a
1
b
1
)
∗
.
.
.
∗
(
a
n
0
+
a
n
1
+
.
.
+
a
n
b
n
)
总的约数之和为(a_{1}^0 + a_{1}^1 +...+a_1^{b1})*...*(a_{n}^0 + a_{n}^1 +..+a_n^{bn})
总的约数之和为(a10+a11+...+a1b1)∗...∗(an0+an1+..+anbn);
以
s
u
m
(
a
,
k
)
代
表
(
a
0
+
a
1
+
.
.
.
+
a
k
)
以sum(a, k)代表(a^0 + a ^ 1 + ... + a^k)
以sum(a,k)代表(a0+a1+...+ak)
若
k
为
奇
数
,
则
k
+
1
为
偶
数
,
有
k
+
1
个
约
数
(
0
−
k
)
若k为奇数,则k+1为偶数,有k+1个约数(0-k)
若k为奇数,则k+1为偶数,有k+1个约数(0−k)
则
s
u
m
(
a
,
k
)
=
(
a
0
+
.
.
.
+
a
k
−
1
2
)
+
(
a
k
+
1
2
+
.
.
.
+
a
k
)
则sum(a, k) = (a ^0 + ... + a^\frac{k-1}{2}) + (a^\frac{k+1}{2} + ...+ a^k)
则sum(a,k)=(a0+...+a2k−1)+(a2k+1+...+ak)
=
(
a
0
+
.
.
.
+
a
k
−
1
2
)
+
a
k
+
1
2
(
a
0
+
.
.
.
+
a
k
−
1
2
)
=(a ^0 + ... + a^\frac{k-1}{2}) + a^\frac{k+1}{2} (a^0+ ...+ a^\frac{k-1}{2})
=(a0+...+a2k−1)+a2k+1(a0+...+a2k−1)
提
取
公
因
式
得
s
u
m
(
a
,
k
)
=
(
1
+
a
k
+
1
2
)
∗
s
u
m
(
a
,
k
−
1
2
)
提取公因式得sum(a,k) = (1+a^\frac{k+1}{2})*sum(a, \frac{k-1}{2})
提取公因式得sum(a,k)=(1+a2k+1)∗sum(a,2k−1)
若
k
为
偶
数
,
则
k
+
1
为
奇
数
,
k
−
1
为
偶
数
若k为偶数,则k+1为奇数,k-1为偶数
若k为偶数,则k+1为奇数,k−1为偶数
则
s
u
m
(
a
,
k
)
=
s
u
m
(
a
,
k
−
1
)
+
a
k
则sum(a, k) = sum(a, k - 1) + a^k
则sum(a,k)=sum(a,k−1)+ak
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 9901;
//快速幂
int qmi(int a, int k, int p) // 求a^k mod p
{
//这一步不能少
a %= p;
int res = 1 % p;
while (k)
{
if (k & 1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
int sum(int a, int k){
//结束条件,a^0=1
if(k == 0) return 1;
if(k % 2 == 1){
//k取余2等于1,说明k是奇数,即有偶数个约数
//sum(a,k) = (1+a^(k+1/2))*sum(a, (k-1/2))
return (1 + qmi(a, (k + 1) / 2, mod)) * sum(a, (k - 1) / 2) % mod;
}
//sum(a, k) = sum(a, k - 1) + a^k
return (sum(a, k - 1) + qmi(a, k, mod)) % mod;
}
int main()
{
int A, B;
cin >> A >> B;
//分解质因数
int res = 1;
for(int a = 2; a <= A; a ++){
int k = 0;
while(A % a == 0){
A /= a;
k ++;
}
if(k > 0){
//求解sum(a,k)
res = res * sum(a, B * k) % mod;
}
}
if(A == 0) res = 0;
cout << res;
}
前缀和
s [ i ] = ∑ 1 < = j < = i i a [ j ] s[i] = \sum_{1<=j<=i}^{i}a[j] s[i]=∑1<=j<=iia[j]
差分
d
[
1
]
=
a
[
1
]
d[1] = a[1]
d[1]=a[1]
d
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
(
i
>
=
2
)
d[i] = a[i] - a[i-1](i >= 2)
d[i]=a[i]−a[i−1](i>=2)
差分还原
a
[
i
]
=
a
[
i
−
1
]
+
d
[
i
]
a[i] = a[i - 1] + d[i]
a[i]=a[i−1]+d[i]
二分
前驱二分
while(l < r){
int mid = (l + r + 1) >> 1;
if(a[mid] <= x) l = mid; else r = mid - 1;
}
return a[l];
后继二分
while(l < r){
int mid = l + r >> 1;
if(a[mid] >= x) r = mid; else l = mid + 1;
}
return a[l];
实数域二分
//保留k位小数
int k = 3;
double esp = 10^-(k + 2);
while(l + esp < r){
double mid = (l + r) / 2;
if(calc(mid)) r = mid; else l = mid;
}
深度优先遍历
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2 * 1e5 + 10;
int e[N], ne[N], h[N], idx;
int st[N];
int n;
void add(int a, int b){
e[idx] = b,ne[idx] = h[a], h[a] = idx++;
}
void dfs(int x){
//前序遍历
cout << x;
st[x] = 1;
for (int i = h[x]; i != -1; i = ne[i] ){
int val = e[i];
if(st[val] == 1) continue;
dfs(val);
}
//后序遍历
cout << x;
}
int main()
{
//初始化
memset(h, -1, sizeof h);
scanf("%d", &n);
for (int i = 0; i < n; i ++ ){
int a,b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1);
}
树的深度
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2 * 1e5 + 10;
int e[N], ne[N], h[N], idx;
int st[N], deep[N];
int n;
void add(int a, int b){
e[idx] = b,ne[idx] = h[a], h[a] = idx++;
}
void dfs(int x){
st[x] = 1;
for (int i = h[x]; i != -1; i = ne[i] ){
int val = e[i];
if(st[val] == 1) continue;
//子节点深度是父节点的深度+1
deep[val] = deep[x] + 1;
dfs(val);
}
}
int main()
{
//初始化
memset(h, -1, sizeof h);
scanf("%d", &n);
for (int i = 0; i < n; i ++ ){
int a,b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1);
cout<< deep[n];
}
树的重心
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2 * 1e5 + 10;
int e[N], ne[N], h[N], idx;
int st[N], siz[N];
int n, ans = 1e9, pos;
void add(int a, int b){
e[idx] = b,ne[idx] = h[a], h[a] = idx++;
}
void dfs(int x){
st[x] = 1;
siz[x] = 1;
int maxNode = 0; //最大子树大小
for (int i = h[x]; i != -1; i = ne[i] ){
int val = e[i];
if(st[val] == 1) continue;
dfs(val);
siz[x] += siz[val];
maxNode = max(maxNode, siz[val]);
}
maxNode = max(maxNode, n - siz[x]);
if(maxNode < ans){
ans = maxNode; //最大子节点
pos = x; //重心
}
}
int main()
{
//初始化
memset(h, -1, sizeof h);
scanf("%d", &n);
for (int i = 0; i < n; i ++ ){
int a,b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1);
cout<< pos;
}
广度优先遍历
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 2*1e5 + 10;
int e[N], ne[N], h[N], idx;
queue<int> q;
bool st[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs(){
memset(st, false, sizeof st);
queue<int> q;
q.push(1);
st[1] = true;
while (q.size() > 0){
int x = q.front();
cout << x << endl;
q.pop();
for (int i = h[x]; i != -1; i = ne[i]){
int j = e[i];
if(st[j]) continue;
st[j] = true;
q.push(j);
}
}
}
int main()
{
memset(h, -1, sizeof h);
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++ ){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
bfs();
}
拓扑排序
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int e[N], ne[N], h[N], idx;
int d[N], st[N];
int n,m;
void add(int a, int b){
//a指向b, b入度+1
d[b] += 1;
e[idx] = b, ne[idx]= h[a], h[a] = idx++;
}
void bfs(){
vector<int> v;
queue<int> q;
//入度为0的点入队
for (int i = 1; i <= n; i ++ ){
if(d[i] == 0) q.push(i);
}
while (q.size() > 0){
int x = q.front();
//被访问过的元素打个标记
st[x] = true;
v.push_back(x);
q.pop();
for (int i = h[x]; i != -1; i = ne[i] ){
int y = e[i];
if(st[y]) continue;
//该点指向的所有点入度减1
d[y] -= 1;
//若入度为0,入队
if(d[y] == 0) {
q.push(y);
}
}
}
if(v.size() != n) printf("%d", -1);
else{
for (int i = 0; i < v.size(); i ++ )printf("%d ", v[i]);
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ ){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
bfs();
}