int gcd(int a, int b){
if(b == 0) return a;
return gcd(b, a%b);
}
int lcm(int a, int b){
return a/gcd(a, b)*b;
}
时间复杂度 O ( s q r t ( n ) / 3 ) O(sqrt(n)/3) O(sqrt(n)/3)
根据质数分布规律:大于等于5的质数一定是和6的倍数相邻。
bool check(int x) {
if(x == 2|| x == 3 ||x == 5) return true;
if(x <= 5) return false;
if(x%6 != 1 && x%6 != 5) return false;
for(int i = 5; i*i <= x; i += 6){
if(x % i == 0 || x % (i+2)==0) return false;
}
return true;
}
int primes[N];
bool p[N] = {0};
int k = 0;
void get_primes(){
for(int i = 2; i < N; i++){
if(!p[i]){
primes[k++] = i;
for(int j = i+i; j < N; j += i){
p[j] = 1;
}
}
}
}
时间复杂度 O ( n ) O(n) O(n)
void get_primes(int n){
for(int i = 2; i <= n; i++){
if(!st[i]) {
primes[k++] = i;
}
for(int j = 0; primes[j] <= n/i; j++){
st[primes[j]*i] = true;
if(i % primes[j] == 0) break;//primes[j]是i的最小质因子
}
}
}
时间复杂度几乎 O ( 1 ) O(1) O(1)
void init(){
for(int i = 0; i < n; i++) root[i] = i;
}
int find(int x){
if(root[x] == x) return x;
return root[x] = find(root[x]);
}
void union(int a, int b){
int fa = find(a);
int fb = find(b);
if(fa != fb){
root[fb] = fa; //合并
num[fa] += num[fb]; //统计每个集合的个数
}
}
int Dijkstra(){
memset(d, 0x3f, sizeof d);
d[1] = 0;
for(int i = 0; i < n; i++){ //迭代n次
int u = -1;
for(int j = 1; j <= n; j++)
if(!st[j] && (u == -1 || d[u] > d[j])){
u = j;
}
if(u == -1) return -1;
st[u] = true;
for(int v = 1; v <= n; v++){
d[v] = min(d[v], d[u] + G[u][v]);
}
}
if(d[n] == 0x3f3f3f3f) return -1;
else return d[n];
}
void add(int a, int b, int c){ //加边加权
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a]=idx++;
}
int dijkstra(){
memset(d, 0x3f, sizeof d);
priority_queue<PII, vector<PII>, greater<PII>> pq;
d[1] = 0;
pq.push({0, 1});
while(pq.size()){
auto t = pq.top();
pq.pop();
int ver = t.second, dist = t.first;
if(st[ver]) continue; //用于处理重边和自环
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(d[j] > w[i] + dist){ //注意这里的更新方式, 是从现有的最短距离上,判断加上边权能否改变
d[j] = w[i] + dist;
pq.push({d[j], j});
}
}
}
if(d[n]==0x3f3f3f3f) return -1;
else return d[n];
}
O ( m l o g m ) O(mlogm) O(mlogm)
处理有负权但是没有负环的单源最短路径
这里是用的队列,而Dijkstra堆优化用的是优先队列
int spfa(int s){
memset(d, 0x3f, sizeof d);
d[s] = 0;
queue<int> q;
q.push(1);
st[1] = true; //注意,这里要对在队列中的顶点进行标记
while(q.size()){
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(d[j] > d[t]+ w[i]){
d[j] = d[t]+ w[i];
if(!st[j]){
q.push(j);
st[j] = true;
}
}
}
}
if(d[n] == 0x3f3f3f3f) return -1;
else return d[n];
}
O ( n 3 ) O(n^3) O(n3)
用邻接矩阵存储,通常顶点数小于200
void floyd(){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
}
}
}
}
图使用邻接表存储
bool topsort(){
int cnt = 0;
queue<int> q;
for(int i = 1; i <= n; i++){
if(!ind[i]) q.push(i);
}
while(q.size()){
int t = q.front();
q.pop();
cnt++;
for(int j = 0; j < G[t].size(); j++){
int v = G[t][j];
ind[v]--;
if(!ind[v]) q.push(v);
}
}
if(cnt == n) return 1;
else return 0;
}
区间更新与求和
#define low(x) ((x)&(-x))
void update(int x, int v){
while(x <= n){
c[x] += v;
x += low(x);
}
}
int sum(int x){
int sumx = 0;
while(x){
sumx += c[x];
x -= low(x);
}
return sumx;
}
int son[N][26], cnt[N], idx = 0;
void insert(string &word){
int p = 0;
for(int i = 0; i < word.size(); i++){
int u = word[i] - 'a';
if(son[p][u] == 0) son[p][u] = ++idx;
p = son[p][u];
cnt[p]++;
}
}
int query(string &word){
int p = 0;
for(int i = 0; i < word.size(); i++){
int u = word[i] - 'a';
if(son[p][u] == 0) return 0;
p = son[p][u];
}
return cnt[p];
}
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || root == p || root == q) return root;
auto left = lowestCommonAncestor(root->left, p, q);
auto right = lowestCommonAncestor(root->right, p, q);
if(left && right) return root;
return left == nullptr? right: left;
}
};
for(int i = 1; i <= N; i++){
for(int c = V; c >= w[i]; c--){
dp[c] = max(dp[c], dp[c - w[i]] + v[i]);
}
}
for(int i = 1; i <= N; i++){
for(int c = w[i]; c <= V; c++){
dp[c] = max(dp[c], dp[c - w[i]] + v[i]);
}
}