Min25筛
//注意要存2sqrtN个数。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using int_t = long long int;
using std::cin;
using std::cout;
using std::endl;
const int_t LARGE = 1e5 + 1;
bool isPrime[LARGE + 1];
int_t primes[LARGE + 1];
// S0->所有质数的个数,S1->所有质数的和
int_t S0[LARGE + 1], S1[LARGE + 1];
int_t numbers[LARGE + 1], hash0[LARGE + 1], hash1[LARGE + 1];
int_t g0[LARGE + 1], g1[LARGE];
int_t S1p(int_t n) { return n * (n + 1) / 2; }
void init() {
memset(isPrime, 1, sizeof(isPrime));
isPrime[1] = false;
for (int_t i = 2; i <= LARGE; i++) {
if (isPrime[i]) {
for (int_t j = i * i; j <= LARGE; j += i) {
isPrime[j] = false;
}
primes[++primes[0]] = i;
int_t next = primes[0];
S0[next] = S0[next - 1] + 1;
S1[next] = S1[next - 1] + i;
#ifdef DEBUG
if (i <= 20) {
cout << "prime " << next << " = " << i << " S0 = " << S0[next]
<< " S1 " << S1[next] << endl;
}
#endif
}
}
}
int_t Sphi(int_t n, int_t k, const int_t sqrt, const int_t nx) {
if (n <= 1 || primes[k] > n) return 0;
int_t result = -(S1[k - 1] - S0[k - 1]);
//质数贡献的答案
if (n <= sqrt) {
result += g1[hash0[n]] - g0[hash0[n]];
} else {
result += g1[hash1[nx / n]] - g0[hash1[nx / n]];
}
// #ifdef DEBUG
// cout << "processing n = " << n << " k =" << k << " aka " << primes[k]
// << endl;
// cout << "prime answers " << result << endl;
// #endif
//枚举质因子
for (int_t i = k; primes[i] * primes[i] <= n && i <= primes[0]; i++) {
//枚举质因子的次数
for (int_t p = primes[i]; p * primes[i] <= n; p *= primes[i]) {
//利用积性函数的性质,除掉最小质因子的幂继续递归
result += (Sphi(n / p, i + 1, sqrt, nx)) * (p - p / primes[i]) +
p * primes[i] - p;
}
}
return result;
}
int_t Smu(int_t n, int_t k, const int_t sqrt, const int_t nx) {
if (n <= 1 || primes[k] > n) return 0;
int_t result = -(-S0[k - 1]);
if (n <= sqrt)
result += (-g0[hash0[n]]);
else
result += (-g0[hash1[nx / n]]);
//枚举质因子
for (int_t i = k; primes[i] * primes[i] <= n && i <= primes[0]; i++) {
result += Smu(n / primes[i], i + 1, sqrt, nx) * (-1);
}
return result;
}
void process(int_t n) {
numbers[0] = 0;
int_t sqrt = ::sqrt(n);
// k=0时候的答案
#ifdef DEBUG
cout << "at k = 0" << endl;
#endif
for (int_t i = 1, next; i <= n; i = next + 1) {
next = n / (n / i);
int_t curr = n / i;
int_t id = ++numbers[0];
numbers[id] = curr;
if (curr <= sqrt) {
hash0[curr] = id;
} else {
hash1[n / curr] = id;
}
g0[id] = (n / i) - 1;
g1[id] = S1p(n / i) - 1;
#ifdef DEBUG
cout << "number " << n / i << " id = " << id << " g0 = " << g0[id]
<< " g1 = " << g1[id] << endl;
#endif
}
//从k=1开始
for (int_t k = 1; k <= primes[0]; k++) {
// #ifdef DEBUG
// cout << "before prime " << k << " aka " << primes[k] << endl;
// for (int_t i = 1; i <= numbers[0]; i++) {
// cout << "number " << i << " aka " << numbers[i] << " g0 =
// " << g0[i]
// << " g1 = " << g1[i] << endl;
// }
// #endif
//只有质数平方不超过i才有贡献
for (int_t i = 1;
i <= numbers[0] && primes[k] * primes[k] <= numbers[i]; i++) {
// G(n,k)=G(n,k-1)-f(p_k)(G(n/{p_k})-S_{k-1})
int_t prev;
int_t prevNum = numbers[i] / primes[k];
if (prevNum <= sqrt) {
prev = hash0[prevNum];
} else {
prev = hash1[n / prevNum];
}
// #ifdef DEBUG
// cout << "processing k = " << k << " aka " <<
// primes[k]
// << " i = " << i << " aka " << numbers[i] <<
// endl;
// cout << "i / k prev = " << prev << " aka " <<
// numbers[prev] << endl; cout << "substract g0 for " <<
// (g0[prev] - S0[k - 1]) << " prev "
// << g0[prev] << " prime " << S0[k - 1] << endl;
// #endif
// k是阶段,i才是状态。
g0[i] -= (g0[prev] - S0[k - 1]);
g1[i] -= primes[k] * (g1[prev] - S1[k - 1]);
}
}
#ifdef DEBUG
cout << "g0 = " << g0[hash1[1]] << " g1 = " << g1[hash1[1]] << endl;
int_t _g0 = 0, _g1 = 0;
for (int_t i = 1; i <= n; i++) {
if (isPrime[i]) {
_g0 += 1;
_g1 += i;
}
}
cout << "_g0 = " << _g0 << " _g1 = " << _g1 << endl;
#endif
cout << Sphi(n, 1, sqrt, n) + 1 << " " << Smu(n, 1, sqrt, n) + 1 << endl;
}
int main() {
init();
int_t T;
cin >> T;
while (T--) {
int_t n;
cin >> n;
process(n);
}
return 0;
}
exCRT
#include <algorithm>
#include <iostream>
#include <tuple>
#include <utility>
using int_t = long long int;
using lint_t = __int128_t;
using std::cin;
using std::cout;
using std::endl;
using pair_t = std::pair<int_t, int_t>;
pair_t exgcd(int_t a, int_t b) {
if (b == 0) return pair_t(1, 0);
int_t x, y;
std::tie(x, y) = exgcd(b, a % b);
return pair_t(y, x - (lint_t)(a / b) * y);
}
int_t gcd(int_t a, int_t b) {
if (b == 0) return a;
return gcd(b, a % b);
}
//Ax+By=gcd(A,B) 不论什么情况下,x都可以对B/gcd(A,B)取模
int_t solve(int_t* mods, int_t* coefs, int_t n) {
int_t result = coefs[1], lcm = mods[1];
for (int_t i = 2; i <= n; i++) {
int_t mod = mods[i];
int_t tx;
#ifdef DEBUG
cout << "joining " << coefs[i] << " mod " << mod << endl;
#endif
std::tie(tx, std::ignore) = exgcd(lcm, mod);
#ifdef DEBUG
cout << "raw tx = " << tx << " sx = " << sx << endl;
cout << "to mod " << (mod / gcd(lcm, mod)) << endl;
#endif
tx = (tx % (mod / gcd(lcm, mod)) + (mod / gcd(lcm, mod))) %
(mod / gcd(lcm, mod));
int_t C = ((coefs[i] - result) % mod + mod) % mod;
int_t prod = C / gcd(lcm, mod);
#ifdef DEBUG
cout << "C = " << C << " prod = " << prod << endl;
cout << "tx = " << tx << endl;
#endif
int_t D = mod / gcd(lcm, mod);
//所有涉及乘法的地方都小心爆掉
tx = ((lint_t)tx * prod % D + D) % D;
int_t lcmx = lcm;
lcm = (lint_t)lcm / gcd(lcm, mod) * mod;
result = (result + (lint_t)lcmx * tx) % lcm;
#ifdef DEBUG
cout << "join " << i << " result = " << result << " lcm = " << lcm
<< endl;
#endif
}
return result;
}
int main() {
const int_t LARGE = 1e5;
static int_t mods[LARGE + 1], coefs[LARGE + 1];
int_t n;
scanf("%lld", &n);
for (int_t i = 1; i <= n; i++) scanf("%lld%lld", &mods[i], &coefs[i]);
printf("%lld", solve(mods, coefs, n));
return 0;
}
Pollard Rho
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <inttypes.h>
#include <random>
#define debug(x) std::cout << #x << " = " << x << std::endl;
typedef long long int int_t;
using std::cin;
using std::endl;
using std::cout;
std::mt19937 gen;
int_t mul(int_t a,int_t b,int_t mod){
return (__int128_t) a * b % mod;
}
int_t power(int_t base,int_t index,int_t mod){
int_t result = 1;
while(index){
if(index & 1) result = mul(result,base,mod);
index >>= 1;
base = mul(base,base,mod);
}
return result;
}
bool isPrime(int_t p){
if(p <= 1) return false;
if(p == 2) return true;
int_t s = 0,t = p - 1;
while(t % 2 == 0) {
t/=2;
s+=1;
}
const int_t TRIAL_TIMES = 3;
std::uniform_int_distribution<int_t> rand_int(2,p-1);
for(int_t _ = 1; _ <= TRIAL_TIMES ;_ ++){
int_t a = rand_int(gen);
int_t prev = power(a,t,p);
for(int_t i = 1;i <= s;i ++){
int_t curr = mul(prev,prev,p);
if(curr == 1 && prev != 1 && prev != p - 1) return false;
prev = curr;
}
if(prev != 1) return false;
}
return true;
}
int_t gcd(int_t a,int_t b){
if(b == 0) return a;
return gcd(b,a%b);
}
int_t getFactor(int_t n,int_t c){
const auto f = [=](int_t x)->int_t{
return (mul(x,x,n) + c) % n;
};
std::uniform_int_distribution<int_t> rand_int(2,n-1);
int_t x = rand_int(gen);
int_t y = rand_int(gen);
int_t k = 2,i = 0;
int_t prod = 1,factor = 1;
while(true){
i ++;
x = f(x);
prod = mul(prod,std::abs(y - x),n);
if(i % 256 == 0){
factor = gcd(prod,n);
if(factor > 1) return factor;
}
if(x == y) return n;
if(i == k){
i = 0;
k *= 2;
factor = std::max(factor,gcd(prod,n));
if(factor > 1) return factor;
prod = 1;
y = x;
}
}
}
int_t pollardRho(int_t x){
if(isPrime(x)) return x;
std::uniform_int_distribution<int_t> rand_int(2,x-1);
int_t c = rand_int(gen);
int_t factor = x;
while(factor == x){
factor = getFactor(x,c --);
if(c <= 2) c = gen();
}
return std::max(pollardRho(factor),pollardRho(x / factor));
}
int main() {
gen.seed(std::random_device()());
int_t T;
cin >> T;
while(T --){
int_t x;
cin >> x;
if(isPrime(x)) cout << "Prime" << endl;
else {
cout << pollardRho(x) << endl;
}
}
return 0;
}
01Trie
可以代替用于维护集合的平衡树。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <inttypes.h>
#include <assert.h>
#define debug(x) std::cout << #x << " = " << x << std::endl;
typedef long long int int_t;
using std::cin;
using std::endl;
using std::cout;
const int_t BITS = 25;
const int_t OFFSET = 1e7;
struct Node {
Node* chds[2] = {nullptr,nullptr};
Node* parent = nullptr;
int_t size = 0;
int_t count = 0;
void maintain() {
size = count;
if(chds[0]) size += chds[0] -> size;
if(chds[1]) size += chds[1] -> size;
}
int_t leftSize() {
if(chds[0]) return chds[0] -> size;
return 0;
}
};
Node* root = new Node;
void insert(Node* node,int_t val) {
for(int_t i = BITS - 1; i >= 0; i --) {
int_t bit = (val & (1 << i)) != 0;
auto& chd = node -> chds[bit];
if(chd == nullptr) {
chd = new Node;
chd -> parent = node;
}
node = chd;
}
node -> count += 1;
while(node) {
node -> maintain();
node = node -> parent;
}
}
void remove(Node* node,int_t val) {
for(int_t i = BITS - 1; i >= 0; i --) {
int_t bit = (val & (1 << i)) != 0;
auto& chd = node -> chds[bit];
node = chd;
}
node -> count -= 1;
while(node) {
node -> maintain();
node = node -> parent;
}
}
int_t rank(Node* node,int_t val) {
insert(root,val);
int_t result = 1;
for(int_t i = BITS - 1; i >= 0; i --) {
int_t bit = (val & (1 << i)) != 0;
auto& chd = node -> chds[bit];
if(bit == 1 ) {
result += node -> leftSize();
}
node = chd;
}
remove(root,val);
return result;
}
int_t kth(Node* node,int_t k) {
int_t result = 0;
for(int_t i = BITS - 1; i >= 0; i --) {
if(k <= node -> leftSize()) {
node = node -> chds[0];
} else {
result |= (1 << i);
k -= node -> leftSize();
node = node -> chds[1];
}
}
return result;
}
Node* locate(Node* node,int_t val) {
for(int_t i = BITS - 1; i >= 0; i --) {
int_t bit = (val & (1 << i)) != 0;
auto& chd = node -> chds[bit];
node = chd;
}
return node;
}
int n;
int main() {
scanf("%d",&n);
while(n--) {
int_t opt,val;
scanf("%lld%lld",&opt,&val);
if(opt == 1) {
insert(root,val + OFFSET);
} else if(opt == 2) {
remove(root,val + OFFSET);
} else if(opt == 3) {
printf("%lld\n",rank(root,val + OFFSET));
} else if(opt == 4) {
printf("%lld\n",kth(root,val) - OFFSET);
} else if(opt == 5) {
int_t rank = ::rank(root,val + OFFSET) - 1;
printf("%lld\n",kth(root,rank) - OFFSET);
} else if(opt == 6) {
int_t rank = ::rank(root,val + OFFSET);
int_t count = locate(root,val + OFFSET) -> count;
printf("%lld\n",kth(root,rank + count ) - OFFSET);
}
}
return 0;
}
匈牙利
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <inttypes.h>
#include <cstring>
#define debug(x) std::cout << #x << " = " << x << std::endl;
typedef long long int int_t;
using std::cin;
using std::endl;
using std::cout;
const int_t LARGE = 1000;
std::vector<int_t> graph[LARGE + 1];
int_t lmatch[LARGE + 1],rmatch[LARGE + 1];
bool visited[LARGE + 1];
bool DFS(int_t vtx){
for(int_t to : graph[vtx]){
if(visited[to]) continue;
visited[to] = true;
if(rmatch[to] == -1 || DFS(rmatch[to])){
rmatch[to] = vtx;
lmatch[vtx] = to;
return true;
}
}
return false;
}
int_t n,m,e;
int main() {
cin >> n >> m >> e;
for(int_t i = 1;i <= e;i ++){
int_t left,right;
cin >> left >> right;
if(right > m || left > n) continue;
graph[left].push_back(right);
}
memset(lmatch,-1,sizeof(lmatch));
memset(rmatch,-1,sizeof(rmatch));
int_t result = 0;
for(int_t i = 1;i <= n;i ++){
if(lmatch[i] == -1){
memset(visited,0,sizeof(visited));
if(DFS(i)) result++;
}
}
cout << result << endl;
return 0;
}
KDTree
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <inttypes.h>
#include <utility>
#define debug(x) std::cout << #x << " = " << x << std::endl;
typedef long long int int_t;
using std::cin;
using std::endl;
using std::cout;
const int_t X = 0;
const int_t Y = 1;
const auto COEF = 0.75;
struct Point {
int_t pos[2];
Point(int_t x=0,int_t y=0) {
this->pos[X]=x;
this->pos[Y]=y;
}
int_t& operator[](int_t v) {
return pos[v];
}
};
struct Node {
Node* left = nullptr,* right = nullptr;
Point LD,RU;
Point point;
int_t value = 0;
int_t sum = 0;
int_t size = 0;
Node(Point point,int_t value) {
this -> point = point;
this -> value = value;
maintain();
}
int_t maxSize() {
int_t size = 0;
if(left) size = std::max(left -> size,size);
if(right) size = std::max(right -> size,size);
return size;
}
void updateFrom(Node* node) {
LD[X]=std::min(node->LD[X],LD[X]);
LD[Y]=std::min(node->LD[Y],LD[Y]);
RU[X]=std::max(node->RU[X],RU[X]);
RU[Y]=std::max(node->RU[Y],RU[Y]);
sum += node -> sum;
size += node -> size;
}
void maintain() {
LD = RU = point;
sum = value;
size = 1;
if(left) updateFrom(left);
if(right) updateFrom(right);
}
int_t query(const Point& LD,const Point& RU) {
//ÍêÈ«°üº¬
if(this -> LD[X] >= LD.pos[X] && this -> LD[Y] >= LD.pos[Y] && this -> RU[X] <= RU.pos[X] && this -> RU[Y] <= RU.pos[Y]) {
return this -> sum;
}
//ÍêÈ«²»°üº¬
if(RU.pos[X] < this -> LD.pos[X] || RU.pos[Y] < this -> LD.pos[Y] || LD.pos[X] > this -> RU.pos[X] || LD.pos[Y] > this -> RU.pos[Y]) return 0;
int_t sum = 0;
if(this->point[X] >= LD.pos[X] && this -> point[X] <= RU.pos[X] && this -> point[Y] >= LD.pos[Y] && this -> point[Y] <= RU.pos[Y]) sum += this -> value;
if(left) sum += left -> query(LD,RU);
if(right) sum += right -> query(LD,RU);
return sum;
}
};
using pair_t = std::pair<Point,int_t>;
Node* build(pair_t* left,pair_t* right,int_t dir = 0) {
if(left > right) return nullptr;
pair_t* mid = left + (right - left + 1) / 2;
std::nth_element(left,mid,right + 1,[=](const pair_t& a,const pair_t& b) {
return a.first.pos[dir] < b.first.pos[dir];
});
Node* node = new Node(mid -> first,mid -> second);
node -> left = build(left,mid-1,dir ^ 1);
node -> right = build(mid + 1,right,dir ^ 1);
node -> maintain();
return node;
}
void walk(Node* root,std::vector<pair_t> & output) {
if(root==nullptr) return;
walk(root -> left,output);
Node* right = root -> right;
output.push_back(pair_t(root -> point,root -> value));
delete root;
walk(right,output);
}
Node* rebuild(Node* root,int_t dir) {
std::vector<pair_t> output;
walk(root,output);
Node* result = build(&output[0],&output.back(),dir);
return result;
}
Node* insert(Node* root,const Point& point,int_t value,int_t dir = 0) {
if(root == nullptr) {
return new Node(point,value);
}
if(point.pos[dir] < root->point[dir]) {
root -> left = insert(root -> left,point,value,dir ^ 1);
} else {
root -> right = insert(root -> right,point,value,dir ^ 1);
}
root -> maintain();
if((double)root -> maxSize() / root -> size > COEF) {
root = rebuild(root,dir);
}
return root;
}
int main() {
int_t n;
cin >> n;
int_t lastans = 0;
Node* root = nullptr;
while(true) {
int opt;
scanf("%d",&opt);
if(opt == 1) {
int_t x,y,val;
scanf("%lld%lld%lld",&x,&y,&val);
x^=lastans;
y^=lastans;
val^=lastans;
root = insert(root,Point(x,y),val);
} else if(opt == 2) {
int_t x1,y1,x2,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
x1^=lastans;
x2^=lastans;
y1^=lastans;
y2^=lastans;
if(root == nullptr) lastans = 0;
else lastans = root -> query(Point(x1,y1),Point(x2,y2));
printf("%lld\n",lastans);
}else if(opt==3){
break;
}
}
return 0;
}