mirror of
https://github.com/Kiritow/OJ-Problems-Source.git
synced 2024-03-22 13:11:29 +08:00
Add files via upload
This commit is contained in:
parent
3149f4bf0d
commit
299b05c265
27
.ACM-Templates/TXTs/分数.txt
Normal file
27
.ACM-Templates/TXTs/分数.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
//·ÖÊýÀà
|
||||
struct Frac {
|
||||
ll a, b; //·Ö×Ó, ·Öĸ
|
||||
Frac(const ll &_a = 0, const ll &_b = 1): a(_a), b(_b) {
|
||||
if (b < 0) { a = -a; b = -b; }
|
||||
ll t = __gcd(a, b); a /= t, b /= t;
|
||||
}
|
||||
Frac operator-()const { return Frac(-a, b); }
|
||||
Frac operator+(const Frac &r)const { return Frac(a * r.b + r.a * b, b * r.b); }
|
||||
Frac operator-(const Frac &r)const { return Frac(a * r.b - r.a * b, b * r.b); }
|
||||
Frac operator*(const Frac &r)const { return Frac(a * r.a, b * r.b); }
|
||||
Frac operator/(const Frac &r)const { return Frac(a * r.b, b * r.a); }
|
||||
Frac &operator+=(const Frac &r) { return *this = *this + r; }
|
||||
Frac &operator-=(const Frac &r) { return *this = *this - r; }
|
||||
Frac &operator*=(const Frac &r) { return *this = *this * r; }
|
||||
Frac &operator/=(const Frac &r) { return *this = *this / r; }
|
||||
bool operator<(const Frac &r)const { return a * r.b < r.a * b; }
|
||||
bool operator>(const Frac &r)const { return a * r.b > r.a * b; }
|
||||
bool operator==(const Frac &r)const { return a * r.b == r.a * b; }
|
||||
bool operator!=(const Frac &r)const { return a * r.b != r.a * b; }
|
||||
bool operator<=(const Frac &r)const { return a * r.b <= r.a * b; }
|
||||
bool operator>=(const Frac &r)const { return a * r.b >= r.a * b; }
|
||||
void print() { if (b == 1) { printf("%I64d", a); } else { printf("%I64d/%I64d", a, b); } }
|
||||
friend ostream &operator<<(ostream &out, const Frac &r) {
|
||||
if (r.b == 1) { out << r.a; } else { out << r.a << '/' << r.b; } return out;
|
||||
}
|
||||
};
|
2263
.ACM-Templates/TXTs/图论模板.txt
Normal file
2263
.ACM-Templates/TXTs/图论模板.txt
Normal file
File diff suppressed because it is too large
Load Diff
1008
.ACM-Templates/TXTs/基础模板.txt
Normal file
1008
.ACM-Templates/TXTs/基础模板.txt
Normal file
File diff suppressed because it is too large
Load Diff
401
.ACM-Templates/TXTs/字符串.txt
Normal file
401
.ACM-Templates/TXTs/字符串.txt
Normal file
|
@ -0,0 +1,401 @@
|
|||
//hash_fun.h
|
||||
inline size_t __stl_hash_string(const char *s) {
|
||||
size_t h = 0;
|
||||
for (; *s; ++s) { h = 5 * h + *s; }
|
||||
return h;
|
||||
}
|
||||
//for hash_map<string, XXX>
|
||||
struct str_hash {
|
||||
size_t operator()(const string &str)const {
|
||||
return __stl_hash_string(str.c_str());
|
||||
}
|
||||
};
|
||||
//BKDR Hash Function
|
||||
inline size_t BKDRHash(const char *str) {
|
||||
size_t h = 0, seed = 131; //31 131 1313 13131 131313 etc..
|
||||
while (*str) { h = h * seed + (*str++); }
|
||||
return h & 0x7FFFFFFF;
|
||||
}
|
||||
//字符串hash
|
||||
const int N = 20005, P = 31, D = 1000173169;
|
||||
int n, pp[N] = {1}, hs[N]; char s[N];
|
||||
int get(int l, int r) { return ((hs[r] - (ll)hs[l - 1] * pp[r - l + 1]) % D + D) % D; }
|
||||
int main() {
|
||||
scanf("%d%s", &n, s + 1);
|
||||
for (int i = 1; i <= n; i++) { pp[i] = pp[i - 1] * P % D; }
|
||||
for (int i = 1; i <= n; i++) { hs[i] = ((ll)hs[i - 1] * P + s[i]) % D; }
|
||||
}
|
||||
//手写hash_map
|
||||
const int P = 13131;
|
||||
char key[N][M];
|
||||
typedef struct Node { int id, val; } etype;
|
||||
template<size_t(*Hash)(const char *)> struct hashmap {
|
||||
vector<etype> hs[P];
|
||||
void init() { for (int i = 0; i < P; i++) { hs[i].clear(); } }
|
||||
void insert(int id, int val) {
|
||||
int h = Hash(key[id]) % P; hs[h].push_back((etype) {id, val});
|
||||
}
|
||||
bool erase(char *buf) {
|
||||
int h = Hash(buf) % P;
|
||||
for (size_t i = 0; i < n; i++) { if (!strcmp(buf, key[hs[h][i].id])) { hs[h].erase(hs[h].begin() + i); return true; } }
|
||||
return false;
|
||||
}
|
||||
int query(char *buf) {
|
||||
int h = Hash(buf) % P;
|
||||
for (size_t i = 0; i < n; i++) { if (!strcmp(buf, key[hs[h][i].id])) { return hs[h][i].val; } }
|
||||
return false;
|
||||
}
|
||||
};
|
||||
hashmap<BKDRHash> mp;
|
||||
//Manacher 最长回文子串
|
||||
//最长回文子串对应原串T中的位置: l = (i - R[i]) / 2; r = (i + R[i]) / 2 - 2;
|
||||
char s[N], tmp[N << 1];
|
||||
int dp[N << 1];
|
||||
void Manacher(char *s, int len) {
|
||||
int l = 0, mx = 0, id = 0; tmp[l++] = '$'; tmp[l++] = '#';
|
||||
for (int i = 0; i < len; i++) { tmp[l++] = s[i]; tmp[l++] = '#'; }
|
||||
tmp[l] = 0;
|
||||
for (int i = 0; i < l; i++) {
|
||||
dp[i] = mx > i ? min(dp[(id << 1) - i], mx - i) : 1;
|
||||
while (tmp[i + dp[i]] == tmp[i - dp[i]]) { dp[i]++; }
|
||||
if (i + dp[i] > mx) { mx = i + dp[i]; id = i; }
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
while (~scanf("%s", s)) {
|
||||
int len = strlen(s), mlen = (len << 1) + 2, mxlen = 0, mxpos = 0;
|
||||
Manacher(s, len);
|
||||
for (int i = 0; i < mlen; i++) {
|
||||
if (mxlen < dp[i]) { mxlen = dp[i]; mxpos = i; }
|
||||
}
|
||||
printf("%d\n", mxlen - 1); //s.substr((mxpos - mxlen) >> 1, mxlen - 1);
|
||||
}
|
||||
}
|
||||
//字符串最小表示
|
||||
int minString(char *s) {
|
||||
int m = strlen(s), i, j, k;
|
||||
char ss[m << 1]; strcpy(ss, s); strcpy(ss + m, s);
|
||||
for (i = k = 0, j = 1; k < m && i < m && j < m;) {
|
||||
for (k = 0; k < m && ss[i + k] == ss[j + k]; k++);
|
||||
if (k < m) {
|
||||
if (ss[i + k] > ss[j + k]) { i += k + 1; } //最大则改为<
|
||||
else { j += k + 1; }
|
||||
if (i == j) { j++; }
|
||||
}
|
||||
}
|
||||
return min(i, j);
|
||||
}
|
||||
//strstr 在str1中查找str2的第一次出现 无则返回NULL
|
||||
char *strstr(const char *str1, const char *str2);
|
||||
//KMP O(M + N)
|
||||
//nxt[]的含义:x[i-nxt[i]...i-1]=x[0...nxt[i]-1]
|
||||
//nxt[i]为满足x[i-z...i-1]=x[0...z-1]的最大z值(就是x的自身匹配)
|
||||
char x[N], y[N];
|
||||
int nxt[N];
|
||||
void getnxt(char *x, int m, int nxt[]) {
|
||||
int i = 0, j = -1; nxt[0] = -1;
|
||||
while (i < m) {
|
||||
while (j != -1 && x[i] != x[j]) { j = nxt[j]; }
|
||||
nxt[++i] = ++j;
|
||||
}
|
||||
}
|
||||
//改进版
|
||||
void getnxt(char *x, int m, int nxt[]) {
|
||||
int i = 0, j = -1; nxt[0] = -1;
|
||||
while (i < m) {
|
||||
while (j != -1 && x[i] != x[j]) { j = nxt[j]; }
|
||||
if (x[++i] == x[++j]) { nxt[i] = nxt[j]; }
|
||||
else { nxt[i] = j; }
|
||||
}
|
||||
}
|
||||
//返回x在y中出现的次数, 可以重叠
|
||||
//x是模式串, y是主串
|
||||
int KMPCount(char *x, int m, char *y, int n, int nxt[]/*, int &longest, int &lp*/) {
|
||||
int i = 0, j = 0, ans = 0; //longest = 0; lp = 0;
|
||||
while (i < n) {
|
||||
while (j != -1 && y[i] != x[j]) { j = nxt[j]; }
|
||||
i++; j++;
|
||||
//if (j > longest) { longest = j; lp = i - j; }
|
||||
if (j >= m) { j = nxt[j]; ans++; }
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
//扩展KMP
|
||||
//nxt[i]:x[i...m-1]与x[0...m-1]的最长公共前缀
|
||||
//ext[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
|
||||
int nxt[N], ext[N];
|
||||
void getnxt(char *x, int m, int nxt[]) {
|
||||
int i = 2, j = 0, k = 1;
|
||||
while (j + 1 < m && x[j] == x[j + 1]) { j++; }
|
||||
nxt[0] = m; nxt[1] = j;
|
||||
for (; i < m; i++) {
|
||||
int p = nxt[k] + k - 1, l = nxt[i - k];
|
||||
if (i + l < p + 1) { nxt[i] = l; }
|
||||
else {
|
||||
j = max(0, p - i + 1);
|
||||
while (i + j < m && x[i + j] == x[j]) { j++; }
|
||||
nxt[i] = j; k = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
void getext(char *x, int m, char *y, int n, int nxt[], int ext[]) {
|
||||
getnxt(x, m);
|
||||
int i = 1, j = 0, k = 0;
|
||||
while (j < n && j < m && x[j] == y[j]) { j++; }
|
||||
ext[0] = j;
|
||||
for (; i < n; i++) {
|
||||
int p = ext[k] + k - 1, l = nxt[i - k];
|
||||
if (i + l < p + 1) { ext[i] = l; }
|
||||
else {
|
||||
j = max(0, p - i + 1);
|
||||
while (i + j < n && j < m && y[i + j] == x[j]) { j++; }
|
||||
ext[i] = j; k = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Sunday
|
||||
int Sunday(char *x, int m, char *y, int n) {
|
||||
int nxt[26] = {0};
|
||||
for (int j = 0; j < 26; j++) { nxt[j] = m + 1; }
|
||||
for (int j = 0; j < m; j++) { nxt[x[j] - 'a'] = m - j; }
|
||||
for (int pos = 0, i, j; pos <= n - m;) {
|
||||
for (i = pos, j = 0; j < m; i++, j++) {
|
||||
if (y[i] != x[j]) { pos += nxt[y[pos + m] - 'a']; break; }
|
||||
}
|
||||
if (j == m) { return pos; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//Rabin-Karp
|
||||
#define UNSIGNED(x) ((unsigned char)x)
|
||||
const int d = 257;
|
||||
int hashMatch(char *s, int m, char *p, int n) {
|
||||
if (m > n || m == 0 || n == 0) { return -1; }
|
||||
//sv为s子串的hash结果, pv为p的hash结果, base为d的m-1次方
|
||||
unsigned sv = UNSIGNED(s[0]), pv = UNSIGNED(p[0]), base = 1;
|
||||
int i, j;
|
||||
//初始化sv, pv, base
|
||||
for (i = 1; i < m; i++) {
|
||||
pv = pv * d + UNSIGNED(p[i]);
|
||||
sv = sv * d + UNSIGNED(s[i]);
|
||||
base *= d;
|
||||
}
|
||||
i = m - 1;
|
||||
do {
|
||||
if (!(sv ^ pv)) {
|
||||
for (j = 0; j < m && s[i - m + 1 + j] == p[j]; j++);
|
||||
if (j == m) { return i - m + 1; }
|
||||
}
|
||||
if (++i >= n) { break; }
|
||||
//O(1)时间内更新sv, sv + UNSIGNED(s[i - m]) * (~base + 1)等价于sv - UNSIGNED(s[i - m]) * base
|
||||
sv = (sv + UNSIGNED(s[i - m]) * (~base + 1)) * d + UNSIGNED(s[i]);
|
||||
} while (i < n);
|
||||
return -1;
|
||||
}
|
||||
//Trie
|
||||
//数组实现
|
||||
struct Trie {
|
||||
int nxt[N * 20][26], val[N * 20], root, tot;
|
||||
void init() { memset(nxt, 0, sizeof(nxt)); memset(val, 0, sizeof(val)); root = tot = 1; }
|
||||
void insert(char *buf, int id) {
|
||||
int len = strlen(buf), now = root;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
if (!nxt[now][c = buf[i] - 'a']) { nxt[now][c] = ++tot; }
|
||||
now = nxt[now][c];
|
||||
}
|
||||
val[now] = id;
|
||||
}
|
||||
int query(char *buf) {
|
||||
int len = strlen(buf), now = root;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
if (!nxt[now][c = buf[i] - 'a']) { return -1; }
|
||||
now = nxt[now][c];
|
||||
}
|
||||
return val[now];
|
||||
}
|
||||
} tr;
|
||||
//指针实现
|
||||
struct Node { Node *nxt[26]; int val; };
|
||||
struct Trie {
|
||||
Node *root;
|
||||
void init() { erase(root); root = new Node(); }
|
||||
void insert(char *buf, int id) {
|
||||
int len = strlen(buf); Node *now = root;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
if (!now->nxt[c = buf[i] - 'a']) { now->nxt[c] = new Node(); }
|
||||
now = now->nxt[c];
|
||||
}
|
||||
now->val = id;
|
||||
}
|
||||
void erase(Node *p) {
|
||||
if (p) { for (int i = 0; i < 26; i++) { erase(p->nxt[i]); } delete p; }
|
||||
}
|
||||
int query(char *buf) {
|
||||
int len = strlen(buf); Node *now = root;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
if (!now->nxt[c = buf[i] - 'a']) { return -1; }
|
||||
now = now->nxt[c];
|
||||
}
|
||||
return now->val;
|
||||
}
|
||||
} tr;
|
||||
//AC自动机
|
||||
struct AC {
|
||||
int nxt[N * 20][26], fail[N * 20], val[N * 20], root, tot;
|
||||
void init() { memset(nxt, 0, sizeof(nxt)); memset(val, 0, sizeof(val)); root = tot = 1; }
|
||||
void insert(char *buf, int id) {
|
||||
int len = strlen(buf), now = root;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
if (!nxt[now][c = buf[i] - 'a']) { nxt[now][c] = ++tot; }
|
||||
now = nxt[now][c];
|
||||
}
|
||||
val[now] = id;
|
||||
}
|
||||
void build() {
|
||||
queue<int> que; fail[root] = root;
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (!nxt[root][i]) { nxt[root][i] = root; }
|
||||
else { fail[nxt[root][i]] = root; que.push(nxt[root][i]); }
|
||||
}
|
||||
while (!que.empty()) {
|
||||
int now = que.front(); que.pop();
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (!nxt[now][i]) { nxt[now][i] = nxt[fail[now]][i]; }
|
||||
else { fail[nxt[now][i]] = nxt[fail[now]][i]; que.push(nxt[now][i]); }
|
||||
}
|
||||
}
|
||||
}
|
||||
int query(char *buf) {
|
||||
int len = strlen(buf), now = root, res = 0;
|
||||
for (int i = 0, c; i < len; i++) {
|
||||
for (int tmp = now = nxt[now][c = buf[i] - 'a']; tmp != root; tmp = fail[tmp]) {
|
||||
res += val[tmp]; //val[tmp] = 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} ac;
|
||||
//后缀数组
|
||||
//n:串长
|
||||
//m:字符集大小
|
||||
//s[0..n - 1]:字符串
|
||||
//sa[1..n]:字典序第 i 小的是哪个后缀
|
||||
//rnk[0..n - 1]:后缀 i 的排名
|
||||
//height[i]:lcp(sa[i], sa[i - 1])
|
||||
int rnk[N], sa[N], height[N], tmp[N], cnt[N];
|
||||
void SA(char *s, int n, int m) {
|
||||
int i, j, k; n++;
|
||||
memset(rnk, 0, sizeof(rnk)); memset(sa, 0, sizeof(sa)); memset(height, 0, sizeof(height));
|
||||
memset(tmp, 0, sizeof(tmp)); memset(cnt, 0, sizeof(cnt));
|
||||
for (i = 0; i < n; i++) { cnt[rnk[i] = s[i]]++; }
|
||||
for (i = 1; i < m; i++) { cnt[i] += cnt[i - 1]; }
|
||||
for (i = 0; i < n; i++) { sa[--cnt[rnk[i]]] = i; }
|
||||
for (k = 1; k <= n; k <<= 1) {
|
||||
for (i = 0; i < n; i++) {
|
||||
j = sa[i] - k;
|
||||
if (j < 0) { j += n; }
|
||||
tmp[cnt[rnk[j]]++] = j;
|
||||
}
|
||||
sa[tmp[cnt[0] = 0]] = j = 0;
|
||||
for (i = 1; i < n; i++) {
|
||||
if (rnk[tmp[i]] != rnk[tmp[i - 1]] || rnk[tmp[i] + k] != rnk[tmp[i - 1] + k]) { cnt[++j] = i; }
|
||||
sa[tmp[i]] = j;
|
||||
}
|
||||
memcpy(rnk, sa, n * sizeof(int));
|
||||
memcpy(sa, tmp, n * sizeof(int));
|
||||
if (j >= n - 1) { break; }
|
||||
}
|
||||
for (j = rnk[height[i = k = 0] = 0]; i < n - 1; i++, k++) {
|
||||
while (k >= 0 && s[i] != s[sa[j - 1] + k]) { height[j] = k--, j = rnk[sa[j] + 1]; }
|
||||
}
|
||||
}
|
||||
//后缀自动机
|
||||
const int N = 1000005;
|
||||
const int N_CHAR = 26;
|
||||
struct SuffixAutomaton {
|
||||
struct Node { Node *fail, *next[N_CHAR]; int val, right; };
|
||||
Node mempool[N << 1]; int n_node;
|
||||
Node *new_node(int v) {
|
||||
Node *p = &mempool[n_node++]; memset(p->next, 0, sizeof(p->next));
|
||||
p->fail = 0; p->right = 0; p->val = v; return p;
|
||||
}
|
||||
Node *root, *last;
|
||||
SuffixAutomaton() { clear(); }
|
||||
void clear() { root = last = new_node(n_node = 0); }
|
||||
void add(int c) {
|
||||
Node *p = last, *np = new_node(p->val + 1);
|
||||
while (p && !p->next[c]) { p->next[c] = np; p = p->fail; }
|
||||
if (!p) { np->fail = root; }
|
||||
else {
|
||||
Node *q = p->next[c];
|
||||
if (p->val + 1 == q->val) { np->fail = q; }
|
||||
else {
|
||||
Node *nq = new_node(p->val + 1);
|
||||
for (int i = 0; i < N_CHAR; i++) { nq->next[i] = q->next[i]; }
|
||||
nq->fail = q->fail; q->fail = np->fail = nq;
|
||||
while (p && p->next[c] == q) { p->next[c] = nq; p = p->fail; }
|
||||
}
|
||||
}
|
||||
last = np; np->right = 1;
|
||||
}
|
||||
Node *go(const char *s) {
|
||||
Node *p = root; int cL = 0; //与s匹配的长度
|
||||
for (int i = 0; s[i]; i++) {
|
||||
int c = s[i] - 'a';
|
||||
if (p->next[c]) { p = p->next[c], ++cL; }
|
||||
else {
|
||||
while (p && !p->next[c]) { p = p->fail; }
|
||||
if (!p) { cL = 0; p = root; }
|
||||
else { cL = p->val + 1; p = p->next[c]; }
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
int d[N << 1]; Node *b[N << 1];
|
||||
void toposort() {
|
||||
for (int i = 0; i <= n_node; i++) { d[i] = 0; }
|
||||
int mx_val = 0;
|
||||
for (int i = 0; i < n_node; i++) { mx_val = max(mx_val, mempool[i].val); d[mempool[i].val]++; }
|
||||
for (int i = 1; i <= mx_val; i++) { d[i] += d[i - 1]; }
|
||||
for (int i = 0; i < n_node; i++) { b[--d[mempool[i].val]] = &mempool[i]; }
|
||||
}
|
||||
void updateright() {
|
||||
toposort();
|
||||
for (int i = n_node - 1; i; i--) { b[i]->fail->right += b[i]->right; }
|
||||
}
|
||||
} sa;
|
||||
//回文树
|
||||
struct PalindromicTree {
|
||||
int nxt[N][26]; //指向的串为当前串两端加上同一个字符构成
|
||||
int fail[N]; //表示失配后跳转到长度小于该串且以该节点表示回文串的最后一个字符结尾的最长回文串表示的节点
|
||||
int cnt[N]; //表示节点表示的本质不同的串的个数(建树时求出的不是完全的, 最后count函数跑一遍以后才是正确的)
|
||||
int num[N]; //表示以节点表示的最长回文串的最右端点为回文串结尾的回文串个数
|
||||
int len[N]; //表示节点表示的回文串长度
|
||||
int S[N]; //表示第i次添加的字符(S[0] = -1(任意一个在串中不会出现的字符))
|
||||
int last; //指向新添加一个字母后所形成的最长回文串表示的节点
|
||||
int n; //表示添加的字符个数
|
||||
int tot; //表示节点个数
|
||||
int newnode(int l) { len[tot] = l; return tot++; }
|
||||
void init() {
|
||||
memset(nxt, 0, sizeof(nxt)); memset(cnt, 0, sizeof(cnt)); memset(len, 0, sizeof(len));
|
||||
newnode(0); newnode(-1); tot = last = n = 0; S[n] = -1; fail[0] = 1;
|
||||
}
|
||||
int getfail(int x) { //失配后找一个尽量最长的
|
||||
while (S[n - len[x] - 1] != S[n]) { x = fail[x]; }
|
||||
return x;
|
||||
}
|
||||
void add(int c) {
|
||||
c -= 'a'; S[++n] = c;
|
||||
int cur = getfail(last); //通过上一个回文串找这个回文串的匹配位置
|
||||
if (!nxt[cur][c]) { //如果这个回文串没有出现过, 说明出现了一个新的本质不同的回文串
|
||||
int now = newnode(len[cur] + 2); //新建节点
|
||||
fail[now] = nxt[getfail(fail[cur])][c]; //和AC自动机一样建立fail指针, 以便失配后跳转
|
||||
nxt[cur][c] = now; num[now] = num[fail[now]] + 1;
|
||||
}
|
||||
cnt[last = nxt[cur][c]]++;
|
||||
}
|
||||
void count() {
|
||||
for (int i = tot - 1; i >= 0; i--) { cnt[fail[i]] += cnt[i]; }
|
||||
//父亲累加儿子的cnt, 因为如果fail[v] = u, 则u一定是v的子回文串
|
||||
}
|
||||
} pat;
|
21
.ACM-Templates/TXTs/并查集.txt
Normal file
21
.ACM-Templates/TXTs/并查集.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
//并查集 + 路径压缩 O(logn)
|
||||
int fa[N];
|
||||
void init(int n) { for (int i = 0; i <= n; i++) { fa[i] = i; } }
|
||||
int findfa(int n) { return n == fa[n] ? n : fa[n] = findfa(fa[n]); }
|
||||
inline void unite(int x, int y) {
|
||||
x = findfa(x); y = findfa(y);
|
||||
if (x != y) { fa[y] = x; }
|
||||
}
|
||||
//并查集 + 路径压缩 + 启发式合并 O(alpha(n))
|
||||
int fa[N], rnk[N];
|
||||
void init(int n) { for (int i = 0; i <= n; i++) { fa[i] = i; rnk[i] = 0; } }
|
||||
int findfa(int n) { return n == fa[n] ? n : fa[n] = findfa(fa[n]); }
|
||||
inline void unite(int x, int y) {
|
||||
x = findfa(x); y = findfa(y);
|
||||
if (x != y) {
|
||||
if (rnk[x] > rnk[y]) { fa[y] = x; }
|
||||
else { fa[x] = y; if (rnk[x] == rnk[y]) { rnk[y]++; } }
|
||||
}
|
||||
}
|
||||
//迭代路径压缩
|
||||
int findfa(int n) { while (fa[n] != n) { fa[n] = fa[fa[n]]; n = fa[n]; } return n; }
|
210
.ACM-Templates/TXTs/应用.txt
Normal file
210
.ACM-Templates/TXTs/应用.txt
Normal file
|
@ -0,0 +1,210 @@
|
|||
//Joseph问题 O(n)
|
||||
int Joseph(int n, int m, int s) {
|
||||
int ret = s - 1;
|
||||
for (int i = 2; i <= n; i++) { ret = (ret + m) % i; }
|
||||
return ret + 1;
|
||||
}
|
||||
//O(logn) 0 <= k < n
|
||||
int Joseph(int n, int m, int k) {
|
||||
if (m == 1) { return n - 1; }
|
||||
for (k = k * m + m - 1; k >= n; k = k - n + (k - n) / (m - 1));
|
||||
return k;
|
||||
}
|
||||
//康托展开 fac[]为阶乘 0 <= ans
|
||||
ll Cantor(char *s) {
|
||||
ll ans = 0;
|
||||
for (int i = 0, len = strlen(s); i < len; i++) {
|
||||
int cnt = 0;
|
||||
for (int j = i + 1; j < len; j++) { if (s[j] < s[i]) { cnt++; } }
|
||||
ans += cnt * fac[len - i - 1];
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
//康托展开逆运算 1 <= k <= n!
|
||||
vector<int> revCantor(ll n, ll k) {
|
||||
vector<int> v, ret; k--;
|
||||
for (int i = 1; i <= n; i++) { v.push_back(i); }
|
||||
for (int i = n; i >= 1; i--) {
|
||||
ll t = k / fac[i - 1]; k %= fac[i - 1];
|
||||
sort(v.begin(), v.end());
|
||||
ret.push_back(v[t]); v.erase(v.begin() + t);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//求最大的全为id的子矩形面积
|
||||
//单调栈 O(nm)
|
||||
int n, m, a[N][N], h[N];
|
||||
int solve(int id) {
|
||||
int ans = 0;
|
||||
memset(h, 0, sizeof(h));
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) { h[j] = a[i][j] == id ? h[j] + 1 : 0; }
|
||||
stack<int> st; st.push(0);
|
||||
for (int j = 1; j <= m + 1; j++) {
|
||||
while (h[j] < h[st.top()]) {
|
||||
int t = h[st.top()]; st.pop();
|
||||
int w = j - st.top() - 1;
|
||||
ans = max(ans, t * w);
|
||||
}
|
||||
st.push(j);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
//dp 悬线法 O(nm)
|
||||
int n, m, a[N][N], l[N], r[N], h[N];
|
||||
int solve(int id) {
|
||||
int ans = 0;
|
||||
for (int i = 1; i <= m; i++) { l[i] = 1; r[i] = m; h[i] = 0; }
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1, mxl = 1; j <= m; j++) {
|
||||
if (a[i][j] == id) { h[j]++; l[j] = max(l[j], mxl); }
|
||||
else { h[j] = 0; l[j] = 1; r[j] = m; mxl = j + 1; }
|
||||
}
|
||||
for (int j = m, mxr = m; j >= 1; j--) {
|
||||
if (a[i][j] == id) { r[j] = min(r[j], mxr); ans = max(ans, (r[j] - l[j] + 1) * h[j]); }
|
||||
else { mxr = j - 1; }
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
//二叉树前序 + 中序求后序遍历
|
||||
void getPost(char *pre, char *in, int len) {
|
||||
if (len == 0) { return; }
|
||||
int root = 0;
|
||||
for (; root < len && in[root] != *pre; root++);
|
||||
getPost(pre + 1, in, root);
|
||||
getPost(pre + root + 1, in + root + 1, len - root - 1);
|
||||
putchar(*pre);
|
||||
}
|
||||
//求1到n之间1的个数
|
||||
ll countOne(ll n) {
|
||||
ll ret = 0;
|
||||
for (ll m = 1; m <= n; m *= 10) {
|
||||
ll a = n / m, b = n % m;
|
||||
ret += (a + 8) / 10 * m + (a % 10 == 1) * (b + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//求1到n所有数字的数位和的和 数位DP
|
||||
char t[N];
|
||||
ll dp[N][N][N];
|
||||
ll countDigit(char *s) {
|
||||
ll ret = 0;
|
||||
for (int i = 1, n = strlen(s); i <= n; i++) { t[i] = s[i - 1] - '0'; }
|
||||
for (int i = 0; i <= t[1]; i++) { dp[1][i][i == t[1]] = 1; }
|
||||
for (int i = 1; i < n; i++) {
|
||||
for (int j = 1; j <= 900; j++) {
|
||||
if (dp[i][j][0]) {
|
||||
for (int k = 0; k <= 9; k++) { dp[i + 1][j + k][0] += dp[i][j][0]; dp[i + 1][j + k][0] %= M; }
|
||||
}
|
||||
if (dp[i][j][1]) {
|
||||
for (int k = 0; k <= t[i + 1]; k++) { dp[i + 1][j + k][k == t[i + 1]] += dp[i][j][1]; dp[i + 1][j + k][k == t[i + 1]] %= M; }
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 1; j <= 900; j++) { ret += dp[n][j][0] * dp[n][j][1] % M; ret %= M; }
|
||||
return ret;
|
||||
}
|
||||
//树hash
|
||||
int hs[N], P[N]; //一些质数
|
||||
void dfs(int u, int p) {
|
||||
vector<int> t; t.push_back(1);
|
||||
for (int i = 0; i < (int)e[u].size(); i++) {
|
||||
int v = e[u][i];
|
||||
if (v == p) { continue; }
|
||||
dfs(v, u); t.push_back(hs[v]);
|
||||
}
|
||||
sort(t.begin(), t.end()); hs[u] = 0;
|
||||
for (int i = 0; i < (int)t.size(); i++) { hs[u] += t[i] * P[i]; }
|
||||
}
|
||||
for (int j = 1; j <= n; j++) {
|
||||
dfs(j, 0); //cout << j << ' ' << hs[j] << endl;
|
||||
}
|
||||
sort(hs[i] + 1, hs[i] + n + 1); //结果序列
|
||||
//整数划分方案数 O(n^1.5)
|
||||
int n, f[777] = {0, 1, 2, 5, 7}, g[N] = {1};
|
||||
int main() {
|
||||
for (int i = 5; i < 777; i++) { f[i] = 3 + 2 * f[i - 2] - f[i - 4]; }
|
||||
while (~scanf("%d", &n)) {
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; f[j] <= i; j++) {
|
||||
if ((j + 1) >> 1 & 1) { g[i] = (g[i] + g[i - f[j]]) % M; }
|
||||
else { g[i] = ((g[i] - g[i - f[j]]) % M + M) % M; }
|
||||
}
|
||||
}
|
||||
printf("%d\n", g[n]);
|
||||
}
|
||||
}
|
||||
//所有区间gcd的预处理
|
||||
int l[N], v[N];
|
||||
void calGCD {
|
||||
for (int i = 1, j; i <= n; i++) {
|
||||
for (v[i] = a[i], j = l[i] = i; j; j = l[j] - 1) {
|
||||
v[j] = __gcd(v[j], a[i]);
|
||||
while (l[j] > 1 && __gcd(a[i], v[l[j] - 1]) == __gcd(a[i], v[j])) { l[j] = l[l[j] - 1]; }
|
||||
//[l[j]...j, i]区间内的值求gcd均为v[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
//小数转化为分数
|
||||
//把小数转化为分数, 循环部分用()表示
|
||||
void work(char str[]) {
|
||||
int len = strlen(str), cnt1 = 0, cnt2 = 0;
|
||||
ll a = 0, b = 0; bool flag = false;
|
||||
for (int i = 2; i < len; i++) {
|
||||
if (str[i] == '(') { break; }
|
||||
a = a * 10 + str[i] - '0'; cnt1++;
|
||||
}
|
||||
for (int i = 2; i < len; i++) {
|
||||
if (str[i] == '(' || str[i] == ')') { flag = true; continue; }
|
||||
b = b * 10 + str[i] - '0'; cnt2++;
|
||||
}
|
||||
ll p = b - a, q = 0; cnt2 -= cnt1;
|
||||
if (!flag) { p = b; q = 1; cnt2 = 0; }
|
||||
for (int i = 0; i < cnt2; i++) { q = q * 10 + 9; }
|
||||
for (int i = 0; i < cnt1; i++) { q = q * 10; }
|
||||
ll g = gcd(p, q);
|
||||
printf("%I64d/%I64d\n", p / g, q / g);
|
||||
}
|
||||
//分数转化为小数
|
||||
//定理: 有理数a / b(其中0 < a < b,(a, b) = 1)能表示成纯循环小数的充要条件是(b, 10) = 1
|
||||
//定理: 有理数a / b, 0 < a < b, (a, b) = 1, b = (2 ^ α) * (5 ^ β) * b1, (b1, 10) = 1,
|
||||
// b1不等于1,α,β不全为零,则a / b可以表示为纯循环小数,其不循环的位数为u = max(α, β)
|
||||
void work(int n) {
|
||||
bool flag = false;
|
||||
int ans[N] = { 0 }, f[N] = { 0, 1 }, k = 1, cnt = 0;
|
||||
if (n < 0) { n = -n; flag = 1; }
|
||||
while (k && n != 1) {
|
||||
k *= 10; ans[cnt++] = k / n; k %= n;
|
||||
if (f[k]) { break; }
|
||||
f[k] = 1;
|
||||
}
|
||||
if (flag) { printf("-"); }
|
||||
if (n == 1) { puts("1"); }
|
||||
else {
|
||||
printf("0.");
|
||||
for (int i = 0; i < cnt; i++) { printf("%d", ans[i]); }
|
||||
puts("");
|
||||
}
|
||||
}
|
||||
//水仙花数 A023052 Powerful numbers(3): numbers n that are the sum of some fixed power of their digits.
|
||||
int Nar[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 4150, 4151, 8208, 9474, 54748, 92727, 93084,
|
||||
194979, 548834, 1741725, 4210818, 9800817, 9926315, 14459929, 24678050, 24678051, 88593477
|
||||
};
|
||||
//完数 A000396 Perfect numbers n: n is equal to the sum of the proper divisors of n.
|
||||
string str[] = {
|
||||
"6",
|
||||
"28",
|
||||
"496",
|
||||
"8128",
|
||||
"33550336",
|
||||
"8589869056",
|
||||
"137438691328",
|
||||
"2305843008139952128",
|
||||
"2658455991569831744654692615953842176",
|
||||
"191561942608236107294793378084303638130997321548169216",
|
||||
"13164036458569648337239753460458722910223472318386943117783728128",
|
||||
"14474011154664524427946373126085988481573677491474835889066354349131199152128",
|
||||
"23562723457267347065789548996709904988477547858392600710143027597506337283178622239730365539602600561360255566462503270175052892578043215543382498428777152427010394496918664028644534128033831439790236838624033171435922356643219703101720713163527487298747400647801939587165936401087419375649057918549492160555646976"
|
||||
};
|
41
.ACM-Templates/TXTs/排序查找.txt
Normal file
41
.ACM-Templates/TXTs/排序查找.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
//三分 求函数极大值
|
||||
const double EPS = 1e-9;
|
||||
double TS(double l, double r) {
|
||||
while (r - l > EPS) {
|
||||
double mid1 = l + (r - l) / 3.0, mid2 = r - (r - l) / 3.0;
|
||||
if (calc(mid1) > calc(mid2)) { r = mid2; }
|
||||
else { l = mid1; }
|
||||
}
|
||||
return l;
|
||||
}
|
||||
//归并排序 求逆序数
|
||||
ll cnt;
|
||||
void mergeSort(int a[], int l, int r) {
|
||||
if (l >= r) { return; }
|
||||
int mid = (l + r) >> 1;
|
||||
mergeSort(a, l, mid);
|
||||
mergeSort(a, mid + 1, r);
|
||||
vector<int> res(r - l + 1);
|
||||
int i = l, j = mid + 1, k = 0;
|
||||
while (i <= mid && j <= r) {
|
||||
if (a[i] > a[j]) { res[k++] = a[j++]; cnt += mid + 1 - i; }
|
||||
else { res[k++] = a[i++]; }
|
||||
}
|
||||
while (i <= mid) { res[k++] = a[i++]; }
|
||||
while (j <= r) { res[k++] = a[j++]; }
|
||||
for (k = l; k <= r; k++) { a[k] = res[k - l]; }
|
||||
}
|
||||
//快排
|
||||
void quickSort(int a[], int l, int r) {
|
||||
if (l >= r) { return; }
|
||||
int i = l, j = r, v = a[l];
|
||||
while (i < j) {
|
||||
while (i < j && a[j] >= v) { j--; }
|
||||
a[i] = a[j];
|
||||
while (i < j && a[i] <= v) { i++; }
|
||||
a[j] = a[i];
|
||||
}
|
||||
a[i] = v;
|
||||
quickSort(a, l, i - 1);
|
||||
quickSort(a, i + 1, r);
|
||||
}
|
634
.ACM-Templates/TXTs/数学数论.txt
Normal file
634
.ACM-Templates/TXTs/数学数论.txt
Normal file
|
@ -0,0 +1,634 @@
|
|||
//快速幂
|
||||
ll powMod(ll a, ll b, ll m) {
|
||||
ll r = 1;
|
||||
for (a %= m; b; b >>= 1) { if (b & 1) { r = r * a % m; } a = a * a % m; }
|
||||
return r;
|
||||
}
|
||||
//素数筛
|
||||
//Eratosthenes O(nloglogn)
|
||||
const int N = 10000000; //~110ms
|
||||
bitset<N> isprime;
|
||||
void getPrime() {
|
||||
isprime.set(); isprime[0] = isprime[1] = false;
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (isprime[i]) {
|
||||
for (ll j = (ll)i * i; j < N; j += i) { isprime[j] = false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//Euler O(n) prime[0]为个数
|
||||
const int N = 10000000; //~110ms
|
||||
int prime[N]; //3711111 for [2, 10^9)
|
||||
void getPrime() {
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (!prime[i]) { prime[++prime[0]] = i; }
|
||||
for (int j = 1; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
prime[prime[j] * i] = 1;
|
||||
if (i % prime[j] == 0) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//Euler O(n)
|
||||
const int N = 10000000; //~95ms
|
||||
int prime[N >> 3]; bitset<N> isprime;
|
||||
void getPrime() {
|
||||
isprime.set(); isprime[0] = isprime[1] = false;
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (isprime[i]) { prime[++prime[0]] = i; }
|
||||
for (int j = 1; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
isprime[prime[j] * i] = false;
|
||||
if (i % prime[j] == 0) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//[a, b]区间内素数个数
|
||||
bitset<N> isprime, isprimesmall;
|
||||
ll segPrime(ll a, ll b) {
|
||||
ll ret = 0; isprime.set(); isprimesmall.set();
|
||||
for (int i = 2; (ll)i * i <= b; i++) {
|
||||
if (isprimesmall[i]) {
|
||||
for (ll j = (ll)i * i; (ll)j * j <= b; j += i) { isprimesmall[j] = false; }
|
||||
for (ll j = max(2ll, (a + i - 1) / i)) * i; j <= b; j += i) { isprime[j - a] = false; }
|
||||
}
|
||||
}
|
||||
for (ll i = 0; i <= r - l; i++) { ret += isprime[i]; }
|
||||
return ret;
|
||||
}
|
||||
//分解质因数
|
||||
ll factor[100], facCnt;
|
||||
void getFactors(ll x) {
|
||||
facCnt = 0;
|
||||
for (int i = 2, xx = sqrt(x + 0.5); i <= xx; i++) {
|
||||
if (x % i == 0) {
|
||||
factor[facCnt++] = i;
|
||||
while (x % i == 0) { x /= i; }
|
||||
}
|
||||
}
|
||||
if (x != 1) { factor[facCnt++] = x; }
|
||||
}
|
||||
//分解质因数及个数 预处理素数表
|
||||
ll factor[100][2], facCnt;
|
||||
void getFactors(ll x) {
|
||||
facCnt = 0;
|
||||
for (int i = 1; prime[i] <= x / prime[i]; i++) {
|
||||
factor[facCnt][1] = 0;
|
||||
if (x % prime[i] == 0) {
|
||||
factor[facCnt][0] = prime[i];
|
||||
while (x % prime[i] == 0) { factor[facCnt][1]++; x /= prime[i]; }
|
||||
facCnt++;
|
||||
}
|
||||
}
|
||||
if (x != 1) { factor[facCnt][0] = x; factor[facCnt++][1] = 1; }
|
||||
}
|
||||
//Miller-Rabin素性测试 素数返回true 错误(伪素数)概率为1/4^Times
|
||||
const int Times = 7;
|
||||
int WIT[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; //7 bases for n < 2^64
|
||||
ll mulMod(ll a, ll b, ll m) {
|
||||
ll r = 0;
|
||||
for (a %= m, b %= m; b; b >>= 1) { if (b & 1) { r = (r + a) % m; } a = (a << 1) % m; }
|
||||
return r;
|
||||
}
|
||||
ll powMod(ll a, ll b, ll m) {
|
||||
ll r = 1;
|
||||
for (a %= m; b; b >>= 1) { if (b & 1) { r = mulMod(r, a, m); } a = mulMod(a, a, m); }
|
||||
return r;
|
||||
}
|
||||
bool Miller_Rabin(ll n) {
|
||||
if (n == 2) { return true; }
|
||||
if (n < 2 || (n & 1) == 0) { return false; }
|
||||
ll m = n - 1; int k = 0;
|
||||
while ((m & 1) == 0) { k++; m >>= 1; }
|
||||
for (int i = 0; i < Times; i++) {
|
||||
ll a = WIT[i], x = powMod(a, m, n), y = 0;
|
||||
//ll a = rand() % (n - 1) + 1;
|
||||
for (int j = 0; j < k; j++, x = y) {
|
||||
y = mulMod(x, x, n);
|
||||
if (y == 1 && x != 1 && x != n - 1) { return false; }
|
||||
}
|
||||
if (y != 1) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//pollard rho质因素分解
|
||||
//对n进行素因子分解, 存入factor, k设置为107左右即可
|
||||
ll factor[100], facCnt; //质因素分解结果(无序)
|
||||
ll pollard_rho(ll x, ll c) {
|
||||
ll i = 1, k = 2, x0 = rand() % (x - 1) + 1, y = x0;
|
||||
while (true) {
|
||||
x0 = (mulMod(x0, x0, x) + c) % x;
|
||||
ll d = llabs(__gcd(y - x0, x));
|
||||
if (d != 1 && d != x) { return d; }
|
||||
if (y == x0) { return x; }
|
||||
if (++i == k) { y = x0; k <<= 1; }
|
||||
}
|
||||
}
|
||||
void findfac(ll n, int k = 107) {
|
||||
if (n == 1) { return; }
|
||||
if (Miller_Rabin(n)) { factor[facCnt++] = n; return; }
|
||||
ll p = n; int c = k;
|
||||
while (p >= n) { p = pollard_rho(p, c--); } //k值变化, 防止死循环
|
||||
findfac(p, k); findfac(n / p, k);
|
||||
}
|
||||
//求单个数的欧拉函数
|
||||
ll eular(ll n) {
|
||||
ll ret = 1;
|
||||
while ((n & 1) == 0) { n >>= 1; ret <<= 1; }
|
||||
for (ll i = 3; i * i <= n; i += 2) {
|
||||
if (n % i == 0) { n /= i; ret *= i - 1; while (n % i == 0) { n /= i; t *= i; } }
|
||||
}
|
||||
return n > 1 ? ret * (n - 1) : ret;
|
||||
}
|
||||
//欧拉函数筛 O(nloglogn)
|
||||
const int N = 10000000; //~400ms
|
||||
int phi[N] = {0, 1};
|
||||
void getPhi() {
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (!phi[i]) {
|
||||
for (int j = i; j < N; j += i) {
|
||||
if (!phi[j]) { phi[j] = j; } phi[j] -= phi[j] / i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//素数 + 欧拉函数筛 O(n)
|
||||
const int N = 10000000; //~150ms
|
||||
int prime[N >> 3], phi[N] = {0, 1}; bitset<N> isprime;
|
||||
void getPrimePhi() {
|
||||
isprime.set(); isprime[0] = isprime[1] = false;
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (isprime[i]) { prime[++prime[0]] = i; phi[i] = i - 1; }
|
||||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
isprime[k = prime[j] * i] = false;
|
||||
if (i % prime[j] == 0) { phi[k] = phi[i] * prime[j]; break; }
|
||||
phi[k] = phi[i] * (prime[j] - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//素数 + 莫比乌斯函数筛 O(n)
|
||||
const int N = 10000000; //150ms
|
||||
int prime[N >> 3], miu[N] = {0, 1}; bitset<N> isprime;
|
||||
void getPrimeMiu() {
|
||||
isprime.set(); isprime[0] = isprime[1] = false;
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (isprime[i]) { prime[++prime[0]] = i; miu[i] = -1; }
|
||||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
isprime[k = prime[j] * i] = false;
|
||||
if (i % prime[j] == 0) { miu[k] = 0; break; }
|
||||
miu[k] = -miu[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
//素数 + 欧拉函数 + 莫比乌斯函数筛 O(n)
|
||||
const int N = 10000000; //~230ms
|
||||
int prime[N >> 3], phi[N] = {0, 1}, miu[N] = {0, 1}; bitset<N> isnprime;
|
||||
void getPrimePhiMiu() {
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (!isnprime[i]) { prime[++prime[0]] = i; phi[i] = i - 1; miu[i] = -1; }
|
||||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
isnprime[k = prime[j] * i] = true;
|
||||
if (i % prime[j] == 0) { phi[k] = phi[i] * prime[j]; miu[k] = 0; break; }
|
||||
phi[k] = phi[i] * (prime[j] - 1); miu[k] = -miu[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
//素数 + 约数个数筛 O(n)
|
||||
const int N = 10000000; //~200ms
|
||||
bitset<N> isprime;
|
||||
int prime[N >> 3], faccnt[N] = {0, 1}, d[N]; //d[i]表示i的最小质因子的幂次
|
||||
void getPrimeFaccnt() {
|
||||
isprime.set(); isprime[0] = isprime[1] = false;
|
||||
for (int i = 2; i < N; i++) {
|
||||
if (isprime[i]) { prime[++prime[0]] = i; faccnt[i] = 2; d[i] = 1; }
|
||||
for (int j = 1, k; j <= prime[0] && prime[j] * i < N; j++) {
|
||||
isprime[k = prime[j] * i] = false;
|
||||
if (i % prime[j] == 0) {
|
||||
faccnt[k] = faccnt[i] / (d[i] + 1) * (d[i] + 2); d[k] = d[i] + 1; break;
|
||||
}
|
||||
faccnt[k] = faccnt[i] << 1; d[k] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//A^B的约数之和为:
|
||||
//sum = [1+p1+p1^2+...+p1^(a1*B)]*...*[1+pn+pn^2+...+pn^(an*B)].
|
||||
//等比数列求和 1+a+a^2+...+a^b
|
||||
ll sumPow(ll a, ll b, ll m) {
|
||||
ll r = 1; a %= m;
|
||||
for (ll t = 1; b; b >>= 1) {
|
||||
if (b & 1) { r = (r * a + t) % m; }
|
||||
t = t * (a + 1) % m;
|
||||
a = a * a % m;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//求逆元(ax = 1(mod m)的x值)
|
||||
//扩展欧几里得(求ax + by = gcd(a, b)的解), 求出的x为a对b的模逆元
|
||||
ll exgcd(ll a, ll b, ll &x, ll &y) {
|
||||
if (b == 0) { x = 1; y = 0; return a; }
|
||||
ll d = exgcd(b, a % b, y, x); y -= a / b * x; return d;
|
||||
}
|
||||
//解不定方程ax + by = c 求得的只是其中一组解
|
||||
//对于不定整数方程ax + by = c, 若c mod gcd(a, b) = 0, 则该方程存在整数解, 否则不存在整数解
|
||||
//在找到ax + by = gcd(a, b)的一组解x0, y0后,可得到ax + by = c的一组解x1 = x0 * (c / gcd(a, b)), y1 = y0 * (c / gcd(a,b))
|
||||
//ax + by = c的其他整数解满足:
|
||||
//x = x1 + b / gcd(a, b) * t, y = y1 - a / gcd(a, b) * t(其中t为任意整数)
|
||||
//求ax + by = c的一组解
|
||||
bool linear_equation(int a, int b, int c, int &x, int &y) {
|
||||
int d = exgcd(a, b, x, y);
|
||||
if (c % d) { return false; }
|
||||
int k = c / d; x *= k; y *= k; return true;
|
||||
}
|
||||
//求ax = b (mod p)循环节内的所有解
|
||||
ll ans[N], cnt;
|
||||
bool linear_equation(ll a, ll b, ll p) {
|
||||
ll x, y, d = exgcd(a, p, x, y); cnt = 0;
|
||||
if (b % d) { return false; }
|
||||
x = (x % p + p) % p;
|
||||
ans[++cnt] = x * (b / d) % (p / d);
|
||||
for (int i = 1; i < d; i++) { ans[++cnt] = (ans[1] + i * p / d) % n; }
|
||||
return true;
|
||||
}
|
||||
//线性预处理逆元
|
||||
ll Inv[N] = {1, 1};
|
||||
void getInv(int m) {
|
||||
for (ll i = 2; i < m; i++) { Inv[i] = (m - m / i) * Inv[m % i] % m; }
|
||||
}
|
||||
//扩展欧几里得求逆元
|
||||
ll modReverse(ll a, ll m) {
|
||||
ll x, y, d = exgcd(a, m, x, y);
|
||||
if (d == 1) { return (x % m + m) % m; } else { return -1; }
|
||||
}
|
||||
//费马小定理, m为素数, a与m互质
|
||||
ll inv(ll a, ll m) { return powMod(a, m - 2, m); }
|
||||
//只能求0 < a < m的情况,a和m互质
|
||||
ll inv(ll a, ll m) {
|
||||
if (a == 1) { return 1; }
|
||||
return inv(m % a, m) * (m - m / a) % m;
|
||||
}
|
||||
//中国剩余定理 求模线性方程组x = a[i] (mod m[i]) m[i]可以不互质
|
||||
//[1, n]内解的个数为(n - x) / m1 + (x != 0)
|
||||
bool merge(ll a1, ll m1, ll a2, ll m2, ll &a3, ll &m3) {
|
||||
ll d = __gcd(m1, m2), c = a2 - a1;
|
||||
if (c % d != 0) { return false; }
|
||||
c = (c % m2 + m2) % m2 / d; m1 /= d; m2 /= d;
|
||||
c = c * inv(m1, m2) % m2 * m1 * d + a1;
|
||||
m3 = m1 * m2 * d; a3 = (c % m3 + m3) % m3;
|
||||
return true;
|
||||
}
|
||||
ll CRT(ll a[], ll m[], int k) {
|
||||
ll a1 = a[0], m1 = m[0];
|
||||
for (int i = 1; i < k; i++) {
|
||||
ll a2 = a[i], m2 = m[i], m3, a3;
|
||||
if (!merge(a1, m1, a2, m2, a3, m3)) { return -1; }
|
||||
a1 = a3; m1 = m3;
|
||||
}
|
||||
return (a1 % m1 + m1) % m1;
|
||||
}
|
||||
//模线性方程组 需扩展欧几里得
|
||||
//求解方程ax ≡ b (mod m) 相当于求解方程ax + my = b (x, y为整数)
|
||||
int m[10], a[10]; //模数为m, 余数为a, X % m = a
|
||||
bool solve(int &m0, int &a0, int m, int a) {
|
||||
ll y, x, d = exgcd(m0, m, x, y);
|
||||
if (abs(a - a0) % d) { return false; }
|
||||
x *= (a - a0) / d; x %= m / d;
|
||||
a0 = (x * m0 + a0); m0 *= m / d; a0 %= m0;
|
||||
if (a0 < 0) { a0 += m0; }
|
||||
return true;
|
||||
}
|
||||
//无解返回false, 有解返回true
|
||||
//解的形式最后为a0 + m0 * t (0 <= a0 < m0)
|
||||
bool MLES(int &m0, int &a0, int n) { //解为X = a0 + m0 * k
|
||||
bool flag = true; m0 = 1; a0 = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!solve(m0, a0, m[i], a[i])) { flag = false; break; }
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
//求原根
|
||||
ll fac[N];
|
||||
ll getRoot(ll n) {
|
||||
int cnt = 0;
|
||||
for (ll i = 2; i * i < n - 1; i++) { if ((n - 1) % i == 0) { fac[cnt++] = i; fac[cnt++] = (n - 1) / i; } }
|
||||
for (int i = 2, j;; i++) {
|
||||
for (j = 0; j < cnt; j++) { if (powMod(i, fac[j], n) == 1) { break; } }
|
||||
if (j == cnt) { return i; }
|
||||
}
|
||||
}
|
||||
//线性基
|
||||
//异或线性基
|
||||
//若要查询第k小子集异或和, 则把k写成二进制, 对于是1的第i位, 把从低位到高位第i个不为0的数异或进答案
|
||||
//若要判断是否有非空子集的异或和为0, 如果不存在自由基, 那么说明只有空集的异或值为0, 需要高斯消元来判断
|
||||
struct XORBase {
|
||||
int a[64];
|
||||
void clear() { memset(a, 0, sizeof(a)); }
|
||||
void ins(ll x) {
|
||||
for (int i = 62; i >= 0; i--) {
|
||||
if (x & (1 << i)) {
|
||||
if (a[i]) { x ^= a[i]; }
|
||||
else { a[i] = x; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//查询最大子集异或和
|
||||
void query() {
|
||||
ll ret = 0;
|
||||
for (int i = 62; i >= 0; i--) { ret = max(ret, ret ^ a[i]); }
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
//实数线性基
|
||||
//ins返回要插入的数是否可以被之前的数线性表示出来, 返回true表示不能, false表示可以
|
||||
int m;
|
||||
struct Base {
|
||||
double a[N][N]; bool v[N];
|
||||
void clear() { memset(a, 0, sizeof(a)); memset(v, 0, sizeof(v)); }
|
||||
bool ins(double *x) {
|
||||
for (int i = 0; i < m; i++) {
|
||||
if (fabs(x[i]) > 1e-6) {
|
||||
if (v[i]) {
|
||||
double t = x[i] / a[i][i];
|
||||
for (int j = 0; j < m; j++) { x[j] -= t * a[i][j]; }
|
||||
} else {
|
||||
v[i] = 1;
|
||||
for (int j = 0; j < m; j++) { a[i][j] = x[j]; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//离散对数 大步小步算法 Baby-Step Giant-Step
|
||||
//BSGS(a, b, p): 求ax = b (mod p)的最小非负整数解, 若无解则返回 -1
|
||||
//rev(a, p): 扩展欧几里得求逆元
|
||||
//powMod(base, pow, mod): 快速幂
|
||||
//mulMod(a, b, mod): 快速乘(这里用快速乘是为了避免爆long long int, 实际有时可以不用)
|
||||
unordered_map<ll, ll> Hash;
|
||||
ll BSGS(ll a, ll b, ll p) {
|
||||
if (b >= p) { return -1; }
|
||||
a %= p, b %= p;
|
||||
if (!a && !b) { return 1; } //a和b都是p的倍数的话, 就相当于0^x = 0 (mod p)了, 那么最小非负整数解就是1
|
||||
if (!a) { return -1; } //如果a是p的倍数但是b不是, 就相当于0^x = t (mod p), t > 0, 无解
|
||||
Hash.clear();
|
||||
ll m = ceil(sqrt(p)), tmp = 1 % p; //tmp = a^j
|
||||
for (ll j = 0; j < m; j++) { //预处理出a^j mod p的值
|
||||
Hash[tmp] = j; tmp = mulMod(tmp, a, p);
|
||||
}
|
||||
tmp = rev(powMod(a, m, p), p); //tmp = a^(-m)
|
||||
for (ll i = 0; i < m; i++) {
|
||||
if (Hash.find(b) != Hash.end()) { return i * m + Hash[b]; }
|
||||
b = mulMod(b, tmp, p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//高斯消元 求线性方程组的解 O(n^3)
|
||||
//有equ个方程, var个变元, 增广矩阵行数为equ, 列数为var + 1, 下标从0开始
|
||||
int a[N][N], x[N]; //增广矩阵, 解集
|
||||
int freex[N], freenum;//自由变元 (多解枚举自由变元可以使用)
|
||||
//返回值为-1表示无解, 为0是唯一解, 否则返回自由变元个数
|
||||
int Gauss(int equ, int var) {
|
||||
int mxrow, col, k; freenum = 0;
|
||||
for (k = 0, col = 0; k < equ && col < var; k++, col++) {
|
||||
mxrow = k;
|
||||
for (int i = k + 1; i < equ; i++) { if (abs(a[i][col]) > abs(a[mxrow][col])) { mxrow = i; } }
|
||||
if (a[mxrow][col] == 0) { k--; freex[freenum++] = col; continue; } //自由变元
|
||||
if (mxrow != k) { for (int j = col; j <= var; j++) { swap(a[k][j], a[mxrow][j]); } }
|
||||
for (int i = k + 1; i < equ; i++) {
|
||||
if (a[i][col]) {
|
||||
int x = abs(a[i][col]), y = abs(a[k][col]), lcm = x / __gcd(x, y) * y, tx = lcm / x, ty = lcm / y;
|
||||
if (a[i][col] * a[k][col] < 0) { ty = -ty; }
|
||||
for (int j = col; j <= var; j++) {
|
||||
a[i][j] = a[i][j] * tx - a[k][j] * ty; //a[i][j] = (a[i][j] % M + M) % M;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = k; i < equ; i++) { if (a[i][col]) { return -1; } } //无解
|
||||
if (k < var) { return var - k; } //自由变元个数
|
||||
for (int i = var - 1; i >= 0; i--) { //唯一解,回代
|
||||
for (int j = i + 1; j < var; j++) {
|
||||
if (a[i][j]) { a[i][var] -= a[i][j] * x[j]; /*a[i][var] = (a[i][var] % M + M) % M;*/ }
|
||||
}
|
||||
//while (a[i][var] % a[i][i]) { a[i][var] += M; }
|
||||
x[i] = a[i][var] / a[i][i]; //x[i] = (a[i][var] * inv(a[i][i], M)) % M;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//高斯消元 (浮点数)
|
||||
const double eps = 1e-9;
|
||||
const int N = 205;
|
||||
double a[N][N], x[N]; //方程的左边的矩阵和等式右边的值, 求解之后x存的就是结果
|
||||
int equ, var; //方程数和未知数个数
|
||||
//返回0表示无解, 1表示有解
|
||||
int Gauss() {
|
||||
int i, j, k, col, mxrow;
|
||||
for (k = 0, col = 0; k < equ && col < var; k++, col++) {
|
||||
mxrow = k;
|
||||
for (i = k + 1; i < equ; i++) {
|
||||
if (fabs(a[i][col]) > fabs(a[mxrow][col])) { mxrow = i; }
|
||||
}
|
||||
if (fabs(a[mxrow][col]) < eps) { return 0; }
|
||||
if (k != mxrow) {
|
||||
for (j = col; j < var; j++) { swap(a[k][j], a[mxrow][j]); }
|
||||
swap(x[k], x[mxrow]);
|
||||
}
|
||||
x[k] /= a[k][col];
|
||||
for (j = col + 1; j < var; j++) { a[k][j] /= a[k][col]; }
|
||||
a[k][col] = 1;
|
||||
for (i = 0; i < equ; i++) {
|
||||
if (i != k) {
|
||||
x[i] -= x[k] * a[i][k];
|
||||
for (j = col + 1; j < var; j++) { a[i][j] -= a[k][j] * a[i][col]; }
|
||||
a[i][col] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
//自适应simpson积分
|
||||
//给定一个函数f(x), 求[a, b]区间内f(x)到x轴所形成区域的面积
|
||||
double simpson(double l, double r) {return (f(l) + f(r) + 4 * f((l + r) / 2.0)) * (r - l) / 6.0;}
|
||||
double rsimpson(double l, double r) {
|
||||
double mid = (l + r) / 2.0;
|
||||
if (fabs(simpson(l, r) - simpson(l, mid) - simpson(mid, r)) < EPS) {
|
||||
return simpson(l, mid) + simpson(mid, r);
|
||||
}
|
||||
return rsimpson(l, mid) + rsimpson(mid, r);
|
||||
}
|
||||
//FFT O(nlogn)
|
||||
//以下n必须为2的幂, op为1时是求DFT, op为-1时为求IDFT
|
||||
typedef complex<double> comp;
|
||||
const double PI = acos(-1.0);
|
||||
void fft(comp a[], int n, int op) {
|
||||
for (int i = 1, j = 0; i < n - 1; i++) {
|
||||
for (int s = n; j ^= s >>= 1, ~j & s;);
|
||||
if (i < j) { swap(a[i], a[j]); }
|
||||
}
|
||||
for (int i = 1; i < n; i <<= 1) {
|
||||
comp wn(cos(PI / i), op * sin(PI / i));
|
||||
for (int j = 0; j < n; j += i << 1) {
|
||||
comp w(1, 0);
|
||||
for (int k = 0; k < i; k++, w *= wn) {
|
||||
comp x = a[j + k], y = w * a[i + j + k];
|
||||
a[j + k] = x + y; a[i + j + k] = x - y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op == -1) { for (int i = 0; i < n; i++) { a[i] = comp(a[i].real() / n, a[i].imag()); } }
|
||||
}
|
||||
//求高精度乘法 HDU 1402
|
||||
comp a[N], b[N];
|
||||
char str1[N / 2], str2[N / 2];
|
||||
int sum[N];
|
||||
int main() {
|
||||
while (~scanf("%s%s", str1, str2)) {
|
||||
memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b));
|
||||
int n = strlen(str1), m = strlen(str2), len = 1;
|
||||
while (len < n * 2 || len < m * 2) { len <<= 1; }
|
||||
for (int i = 0; i < n; i++) { a[i] = comp(str1[n - 1 - i] - '0', 0); }
|
||||
for (int i = 0; i < m; i++) { b[i] = comp(str2[m - 1 - i] - '0', 0); }
|
||||
fft(a, len, 1); fft(b, len, 1);
|
||||
for (int i = 0; i < len; i++) { a[i] *= b[i]; }
|
||||
fft(a, len, -1);
|
||||
for (int i = 0; i < len; i++) { sum[i] = (int)(a[i].real() + 0.5); }
|
||||
for (int i = 0; i < len; i++) { sum[i + 1] += sum[i] / 10; sum[i] %= 10; }
|
||||
len = n + m - 1;
|
||||
while (sum[len] <= 0 && len > 0) { len--; }
|
||||
for (int i = len; i >= 0; i--) { putchar(sum[i] + '0'); } puts("");
|
||||
}
|
||||
}
|
||||
//NTT O(nlogn)
|
||||
//998244353 = 119 * 2^23 + 1, 原根为3; 1004535809 = 479 * 2^21 + 1, 原根为3
|
||||
//786433 = 3 * 2^18 + 1, 原根为10; 880803841 = 105 * 2^23 + 1, 原根为26
|
||||
//P是素数且N必须是P - 1的因子
|
||||
//op为1时是求FNT, op为-1时为求IFNT
|
||||
const int P = 998244353, G = 3, N = 262144, K = 17;
|
||||
ll g[N + 5], ng[N + 5], Inv[N + 5] = {1, 1};
|
||||
void initG() {
|
||||
g[K] = powMod(G, (P - 1) / N, P); ng[K] = powMod(g[K], P - 2, P);
|
||||
for (int i = K - 1; i >= 0; i--) { g[i] = g[i + 1] * g[i + 1] % P; ng[i] = ng[i + 1] * ng[i + 1] % P; }
|
||||
for (ll i = 2; i <= N; i++) { Inv[i] = (P - P / i) * Inv[P % i] % P; }
|
||||
}
|
||||
void ntt(ll a[], int n, int op) {
|
||||
for (int i = 1, j = 0; i < n - 1; i++) {
|
||||
for (int s = n; j ^= s >>= 1, ~j & s;);
|
||||
if (i < j) { swap(a[i], a[j]); }
|
||||
}
|
||||
for (int d = 0; (1 << d) < n; d++) {
|
||||
int m = 1 << d; ll w0 = op == 1 ? g[d] : ng[d];
|
||||
for (int i = 0; i < n; i += m << 1) {
|
||||
for (int j = 0, w = 1; j < m; j++, w = w * w0 % P) {
|
||||
ll &x = a[i + j + m], &y = a[i + j], t = w * x % P;
|
||||
x = y - t; y = y + t;
|
||||
if (x < 0) { x += P; } if (y >= P) { y -= P; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op == -1) { for (int i = 0; i < n; i++) { a[i] = a[i] * Inv[n] % P; } }
|
||||
}
|
||||
//多项式求逆元 O(nlogn) 即求B(x)满足A(X) * B(x) = 1 (mod x^n), deg(B) <= deg(A)
|
||||
void polyInv(ll a[], ll b[], int n) {
|
||||
if (n == 1) { b[0] = powMod(a[0], P - 2, P); return; }
|
||||
polyInv(a, b, n >> 1);
|
||||
int k = 1;
|
||||
while (k < n << 1) { k <<= 1; }
|
||||
for (int i = 0; i < n; i++) { tmp[i] = a[i]; }
|
||||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||||
ntt(tmp, k, 1); ntt(b, k, 1);
|
||||
for (int i = 0; i < k; i++) {
|
||||
b[i] = b[i] * (2 - tmp[i] * b[i] % P) % P;
|
||||
if (b[i] < 0) { b[i] += P; }
|
||||
}
|
||||
ntt(b, k, -1);
|
||||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||||
}
|
||||
//多项式除法 O(nlogn) 即求D(x)和R(x)满足A(x) = D(x) * B(x) + R(x), deg(D) <= deg(A) - deg(B), deg(R) < deg(B)
|
||||
ll a0[N], b0[N];
|
||||
void polyDiv(ll a[], int n, ll b[], int m, ll d[], ll r[]) {
|
||||
int k = 1, t = n - m + 1;
|
||||
while (k < t << 1) { k <<= 1; }
|
||||
for (int i = 0; i < k; i++) { a0[i] = b0[i] = 0; }
|
||||
for (int i = 0; i < m; i++) { a0[i] = b[m - i - 1]; }
|
||||
polyInv(a0, b0, t);
|
||||
for (int i = t; i < k; i++) { b0[i] = 0; }
|
||||
for (int i = 0; i < t; i++) { a0[i] = a[n - i - 1]; }
|
||||
for (int i = t; i < k; i++) { a0[i] = 0; }
|
||||
ntt(b0, k, 1); ntt(a0, k, 1);
|
||||
for (int i = 0; i < k; i++) { a0[i] = a0[i] * b0[i] % P; }
|
||||
ntt(a0, k, -1);
|
||||
reverse(a0, a0 + t);
|
||||
for (int i = 0; i < t; i++) { d[i] = a0[i]; }
|
||||
for (k = 1; k < n << 1; k <<= 1);
|
||||
for (int i = t; i < k; i++) { a0[i] = 0; }
|
||||
for (int i = 0; i < m; i++) { b0[i] = b[i]; }
|
||||
for (int i = m; i < k; i++) { b0[i] = 0; }
|
||||
ntt(a0, k, 1); ntt(b0, k, 1);
|
||||
for (int i = 0; i < k; i++) { a0[i] = a0[i] * b0[i] % P; }
|
||||
ntt(a0, k, -1);
|
||||
for (int i = 0; i < m; i++) { r[i] = (a[i] - a0[i]) % P; }
|
||||
for (int i = m; i < k; i++) { r[i] = 0; }
|
||||
}
|
||||
//多项式求对数函数 O(nlogn) a[0] = 1
|
||||
void polyLn(ll a[], ll b[], int n) {
|
||||
polyInv(a, tmp2, n);
|
||||
int k = 1;
|
||||
while (k < n << 1) { k <<= 1; }
|
||||
for (int i = 0; i < n - 1; i++) { b[i] = a[i + 1] * (i + 1) % P; }
|
||||
for (int i = n - 1; i < k; i++) { b[i] = 0; }
|
||||
ntt(b, k, 1); ntt(tmp2, k, 1);
|
||||
for (int i = 0; i < k; i++) { b[i] = b[i] * tmp2[i] % P; }
|
||||
ntt(b, k, -1);
|
||||
for (int i = n - 1; i >= 0; i--) { b[i] = b[i - 1] * Inv[i] % P; } b[0] = 0;
|
||||
}
|
||||
//多项式求指数函数 O(nlogn) a[0] = 0
|
||||
void polyExp(ll a[], ll b[], int n) {
|
||||
if (n == 1) { b[0] = 1; return; }
|
||||
polyExp(a, b, n >> 1); polyLn(b, tmp, n);
|
||||
int k = 1;
|
||||
while (k < n << 1) { k <<= 1; }
|
||||
for (int i = 0; i < n; i++) { tmp[i] -= a[i]; if (tmp[i] < 0) { tmp[i] += P; } }
|
||||
if (++tmp[0] == P) { tmp[0] = 0; }
|
||||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||||
ntt(tmp, k, 1); ntt(b, k, 1);
|
||||
for (int i = 0; i < k; i++) { b[i] = b[i] * tmp[i] % P; }
|
||||
ntt(b, k, -1);
|
||||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||||
}
|
||||
//多项式求平方根 O(nlogn) a[0] = 1
|
||||
void polySqrt(ll a[], ll b[], int n) {
|
||||
if (n == 1) { b[0] = 1; return; }
|
||||
polySqrt(a, b, n >> 1); polyInv(b, tmp2, n);
|
||||
int k = 1;
|
||||
while (k < n << 1) { k <<= 1; }
|
||||
for (int i = 0; i < n; i++) { tmp[i] = a[i]; }
|
||||
for (int i = n; i < k; i++) { tmp[i] = b[i] = 0; }
|
||||
ntt(tmp, k, 1); ntt(b, k, 1); ntt(tmp2, k, 1);
|
||||
for (int i = 0; i < k; i++) { b[i] = (b[i] * b[i] + tmp[i]) % P * Inv[2] % P * tmp2[i] % P; }
|
||||
ntt(b, k, -1);
|
||||
for (int i = n; i < k; i++) { b[i] = 0; }
|
||||
}
|
||||
//快速沃尔什变换 即求C[i] = sum{j ? k = i}(A[j] * B[k]) ?为任一二元逻辑位运算
|
||||
void fwt(ll a[], int n) {
|
||||
for (int d = 1; d < n; d <<= 1) {
|
||||
for (int i = 0, m = d << 1; i < n; i += m) {
|
||||
for (int j = 0; j < d; j++) {
|
||||
ll x = a[i + j], y = a[i + j + d];
|
||||
//xor: a[i + j] = x + y; a[i + j + d] = x - y;
|
||||
//and: a[i + j] = x + y;
|
||||
//or: a[i + j + d] = x + y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void ufwt(ll a[], int n) {
|
||||
for (int d = 1; d < n; d <<= 1) {
|
||||
for (int i = 0, m = d << 1; i < n; i += m) {
|
||||
for (int j = 0; j < d; j++) {
|
||||
ll x = a[i + j], y = a[i + j + d];
|
||||
//xor: a[i + j] = (x + y) >> 1; a[i + j + d] = (x - y) >> 1;
|
||||
//and: a[i + j] = x - y;
|
||||
//or: a[i + j + d] = y - x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2209
.ACM-Templates/TXTs/数据结构.txt
Normal file
2209
.ACM-Templates/TXTs/数据结构.txt
Normal file
File diff suppressed because it is too large
Load Diff
456
.ACM-Templates/TXTs/数据结构模板.txt
Normal file
456
.ACM-Templates/TXTs/数据结构模板.txt
Normal file
|
@ -0,0 +1,456 @@
|
|||
============数据结构模板================
|
||||
|
||||
动态树
|
||||
动态树是一类要求维护森林的连通性的题的总称,这类问题要求维护某个点到根的某些数据,支持树的切分,合并,以及对子树的某些操作。其中解决这一问题的某些简化版(不包括对子树的操作)的基础数据结构就是LCT(link-cut tree)。
|
||||
|
||||
const int MAXN = 100010;
|
||||
struct Node
|
||||
{
|
||||
Node *ch[2], *p;
|
||||
int size, value;
|
||||
bool rev;
|
||||
Node(int t = 0);
|
||||
inline bool dir(void)
|
||||
{
|
||||
return p->ch[1] == this;
|
||||
}
|
||||
inline void SetC(Node *x, bool d)
|
||||
{
|
||||
ch[d] = x;
|
||||
x->p = this;
|
||||
}
|
||||
inline void Rev(void)
|
||||
{
|
||||
swap(ch[0], ch[1]);
|
||||
rev ^= 1;
|
||||
}
|
||||
inline void Push(void)
|
||||
{
|
||||
if (rev)
|
||||
{
|
||||
ch[0]->Rev();
|
||||
ch[1]->Rev();
|
||||
rev = 0;
|
||||
}
|
||||
}
|
||||
inline void Update(void)
|
||||
{
|
||||
size = ch[0]->size + ch[1]->size + 1;
|
||||
}
|
||||
} Tnull, *null = &Tnull, *fim[MAXN];
|
||||
// 要记得额外更新null的信息
|
||||
Node::Node(int _value)
|
||||
{
|
||||
ch[0] = ch[1] = p = null;
|
||||
rev = 0;
|
||||
}
|
||||
inline bool isRoot(Node *x)
|
||||
{
|
||||
return x->p == null || (x != x->p->ch[0] && x != x->p->ch[1]);
|
||||
}
|
||||
inline void rotate(Node *x)
|
||||
{
|
||||
Node *p = x->p;
|
||||
bool d = x->dir();
|
||||
p->Push();
|
||||
x->Push();
|
||||
if (!isRoot(p)) p->p->SetC(x, p->dir());
|
||||
else x->p = p->p;
|
||||
p->SetC(x->ch[!d], d);
|
||||
x->SetC(p, !d);
|
||||
p->Update();
|
||||
}
|
||||
inline void splay(Node *x)
|
||||
{
|
||||
x->Push();
|
||||
while (!isRoot(x))
|
||||
{
|
||||
if (isRoot(x->p)) rotate(x);
|
||||
else
|
||||
{
|
||||
if (x->dir() == x->p->dir())
|
||||
{
|
||||
rotate(x->p);
|
||||
rotate(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotate(x);
|
||||
rotate(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
x->Update();
|
||||
}
|
||||
inline Node* Access(Node *x)
|
||||
{
|
||||
Node *t = x, *q = null;
|
||||
for (; x != null; x = x->p)
|
||||
{
|
||||
splay(x);
|
||||
x->ch[1] = q;
|
||||
q = x;
|
||||
}
|
||||
splay(t); //info will be updated in the splay;
|
||||
return q;
|
||||
}
|
||||
inline void Evert(Node *x)
|
||||
{
|
||||
Access(x);
|
||||
x->Rev();
|
||||
}
|
||||
inline void link(Node *x, Node *y)
|
||||
{
|
||||
Evert(x);
|
||||
x->p = y;
|
||||
}
|
||||
inline Node* getRoot(Node *x)
|
||||
{
|
||||
Node *tmp = x;
|
||||
Access(x);
|
||||
while (tmp->Push(), tmp->ch[0] != null) tmp = tmp->ch[0];
|
||||
splay(tmp);
|
||||
return tmp;
|
||||
}
|
||||
// 一定要确定x和y之间有边
|
||||
inline void cut(Node *x, Node *y)
|
||||
{
|
||||
Access(x);
|
||||
splay(y);
|
||||
if (y->p != x) swap(x, y);
|
||||
Access(x);
|
||||
splay(y);
|
||||
y->p = null;
|
||||
}
|
||||
inline Node* getPath(Node *x, Node *y)
|
||||
{
|
||||
Evert(x);
|
||||
Access(y);
|
||||
return y;
|
||||
}
|
||||
inline void clear(void)
|
||||
{
|
||||
null->rev = 0;
|
||||
null->sie = 0;
|
||||
null->value = 0;
|
||||
}
|
||||
|
||||
splay树模板,分为两个部分,第一个部分为splay当作平衡树使用,第二个部分为splay当作线段树维护序列使用。注意在每次Insert之后都要splay其返回值到根
|
||||
// 最大可能的节点数
|
||||
const int MAXN = 100010;
|
||||
// 每个打标记的操作就是更新这个节点的信息,然后对子节点打标记
|
||||
struct Node
|
||||
{
|
||||
Node *ch[2], *p;
|
||||
int size, value;
|
||||
bool rev;
|
||||
inline bool dir(void)
|
||||
{
|
||||
return p->ch[1] == this;
|
||||
}
|
||||
inline void SetC(Node *x, bool d)
|
||||
{
|
||||
ch[d] = x;
|
||||
x->p = this;
|
||||
}
|
||||
inline void Rev(void)
|
||||
{
|
||||
swap(ch[0], ch[1]);
|
||||
rev ^= 1;
|
||||
}
|
||||
// null永远不会push
|
||||
inline void Push(void)
|
||||
{
|
||||
if (rev)
|
||||
{
|
||||
ch[0]->Rev();
|
||||
ch[1]->Rev();
|
||||
rev = 0;
|
||||
}
|
||||
}
|
||||
// null永远不会update
|
||||
inline void Update(void)
|
||||
{
|
||||
size = ch[0]->size + ch[1]->size + 1;
|
||||
}
|
||||
inline void initInfo(void)
|
||||
{
|
||||
rev = 0;
|
||||
}
|
||||
} Tnull, *null = &Tnull, *data, POOL[MAXN];
|
||||
class Splay
|
||||
{
|
||||
public:
|
||||
Node *root;
|
||||
inline void rotate(Node *x)
|
||||
{
|
||||
Node *p = x->p;
|
||||
bool d = x->dir();
|
||||
p->Push();
|
||||
x->Push();
|
||||
p->p->SetC(x, p->dir());
|
||||
p->SetC(x->ch[!d], d);
|
||||
x->SetC(p, !d);
|
||||
p->Update();
|
||||
}
|
||||
inline void splay(Node *x, Node *G)
|
||||
{
|
||||
if (G == null) root = x;
|
||||
while (x->p != G)
|
||||
{
|
||||
if (x->p->p == G) rotate(x);
|
||||
else
|
||||
{
|
||||
if (x->dir() == x->p->dir())
|
||||
{
|
||||
rotate(x->p);
|
||||
rotate(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotate(x);
|
||||
rotate(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
x->Push();
|
||||
x->Update();
|
||||
}
|
||||
inline Node* Renew(int value)
|
||||
{
|
||||
Node *ret = data++;
|
||||
ret->ch[0] = ret->ch[1] =ret->p = null;
|
||||
ret->size = 1;
|
||||
ret->value = value;
|
||||
ret->initInfo();
|
||||
return ret;
|
||||
}
|
||||
inline Node* getMin(Node *x)
|
||||
{
|
||||
Node *tmp = x;
|
||||
while (tmp->ch[0] != null) tmp = tmp->ch[0];
|
||||
return tmp;
|
||||
}
|
||||
inline Node* getMax(Node *x)
|
||||
{
|
||||
Node *tmp = x;
|
||||
while (tmp->ch[1] != null) tmp = tmp->ch[1];
|
||||
return tmp;
|
||||
}
|
||||
// 查询第k大
|
||||
inline Node* getKth(int k)
|
||||
{
|
||||
Node *tmp = root;
|
||||
assert(k > 0 && k <= root->size);
|
||||
while (true)
|
||||
{
|
||||
tmp->Push();
|
||||
if (tmp->ch[0]->size + 1 == k) return tmp;
|
||||
if (tmp->ch[0]->size >= k) tmp = tmp->ch[0];
|
||||
else k -= tmp->ch[0]->size + 1, tmp = tmp->ch[1];
|
||||
}
|
||||
}
|
||||
// 以下为splay当作平衡树使用
|
||||
// 查找树中value = v的元素, 返回之后splay
|
||||
inline Node* find(int v)
|
||||
{
|
||||
Node *tmp = root;
|
||||
while (tmp != null)
|
||||
{
|
||||
tmp->Push();
|
||||
if (tmp->value == v) return tmp;
|
||||
if (v < tmp->value) tmp = tmp->ch[0];
|
||||
else tmp = tmp->ch[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// 统计有多少元素小于等于v, 当flag = 1时,统计多少元素严格小于v, 一定要记得splay最后的那个tmp
|
||||
inline int Count(int v, bool flag = 0)
|
||||
{
|
||||
Node *tmp = root, *last = null;
|
||||
int ret = 0;
|
||||
while (tmp != null)
|
||||
{
|
||||
tmp->Push();
|
||||
last = tmp;
|
||||
if ((!flag && tmp->value > v) || (flag && tmp->value >= v))
|
||||
{
|
||||
tmp = tmp->ch[0];
|
||||
}
|
||||
else ret += tmp->ch[0]->size + 1, tmp = tmp->ch[1];
|
||||
}
|
||||
if (last != null) splay(last, null);
|
||||
return ret;
|
||||
}
|
||||
// 删除x这个结点
|
||||
inline void erase(Node* x)
|
||||
{
|
||||
splay(x, null);
|
||||
if (x->ch[0] == null || x->ch[1] == null)
|
||||
{
|
||||
int d = x->ch[1] != null;
|
||||
root = x->ch[d];
|
||||
root->p = null;
|
||||
return;
|
||||
}
|
||||
Node *L = getMax(x->ch[0]), *R = getMax(x->ch[1]);
|
||||
splay(L, x);
|
||||
splay(R, x);
|
||||
L->SetC(R, 1);
|
||||
L->p = null;
|
||||
root = L;
|
||||
L->Update();
|
||||
}
|
||||
// 插入一个值为value的节点,初始要以Insert(root, null, value)来调用, 返回之后splay
|
||||
inline Node* Insert(Node *&now, Node* father, int value)
|
||||
{
|
||||
if (now == null)
|
||||
{
|
||||
now = Renew(value);
|
||||
now->p = father;
|
||||
return now;
|
||||
}
|
||||
Node *ret;
|
||||
now->Push();
|
||||
if (value <= now->value) ret = Insert(now->ch[0], now, value);
|
||||
else ret = Insert(now->ch[1], now, value);
|
||||
now->Update();
|
||||
return ret;
|
||||
}
|
||||
// 以下为splay维护序列, 初始要在原序列中放入一个-inf和inf来防止边界条件
|
||||
// 得到原数列中[l,r]区间对应的结点,如果l == r + 1则表示是一个空区间
|
||||
inline Node* getInterval(int l, int r)
|
||||
{
|
||||
assert(l <= r + 1);
|
||||
Node *L = getKth(l), *R = getKth(r + 2);
|
||||
splay(L, null);
|
||||
splay(R, L);
|
||||
return R->ch[0];
|
||||
}
|
||||
// 删除一段区间[l,r]
|
||||
inline void eraseInterval(int l, int r)
|
||||
{
|
||||
getInterval(l, r);
|
||||
root->ch[1]->ch[0] = null;
|
||||
root->ch[1]->Update();
|
||||
root->Update();
|
||||
}
|
||||
// 在位置l的后面插入一段区间x (0 <= l <= n)
|
||||
inline void insertInterval(int l, Node *x)
|
||||
{
|
||||
Node *L = getKth(l + 1), *R = getKth(l + 2);
|
||||
splay(L, null);
|
||||
splay(R, L);
|
||||
R->SetC(x, 0);
|
||||
R->Update();
|
||||
L->Update();
|
||||
}
|
||||
// 把数列a的[l,r]构建为一个splay
|
||||
inline Node* Build(int l, int r, int a[])
|
||||
{
|
||||
if (l > r) return null;
|
||||
int mid = (l + r) >> 1;
|
||||
Node *ret = Renew(a[mid]);
|
||||
if (l == r) return ret;
|
||||
ret->SetC(Build(l, mid - 1, a), 0);
|
||||
ret->SetC(Build(mid + 1, r, a), 1);
|
||||
ret->Update();
|
||||
return ret;
|
||||
}
|
||||
} T;
|
||||
void clear(void)
|
||||
{
|
||||
data = POOL;
|
||||
T.root = null;
|
||||
}
|
||||
|
||||
倍增算法构建后缀数组,时间复杂度为 $O(n \lg n)$. 注意字符串和最终的后缀数组均从 1 开始编号. 要保证字符串中都为大于0的字符, 而且字符串的第n+1位应该为0.
|
||||
// string is 1-base, sa is 1-base
|
||||
int w[MAXM];
|
||||
inline void Sort(int a[], int ret[], int n, int m = MAXM - 1)
|
||||
{
|
||||
for (int i = 0; i <= m; i++) w[i] = 0;
|
||||
for (int i = 1; i <= n; i++) w[a[i]]++;
|
||||
for (int i = 1; i <= m; i++) w[i] += w[i - 1];
|
||||
for (int i = n; i >= 1; i--) ret[w[a[i]]--] = i;
|
||||
}
|
||||
int wa[MAXN], wb[MAXN], tmp[MAXN];
|
||||
inline void getSA(int ch[], int sa[], int n)
|
||||
{
|
||||
int *x = wa, *y = wb;
|
||||
for (int i = 1; i <= n; i++) x[i] = ch[i];
|
||||
Sort(ch, sa, n);
|
||||
for (int j = 1, p = 1, m = MAXN - 1; p < n; m = p, j <<= 1)
|
||||
{
|
||||
p = 0;
|
||||
for (int i = n - j + 1; i <= n; i++) y[++p] = i;
|
||||
for (int i = 1; i <= n; i++) if (sa[i] > j) y[++p] = sa[i] - j;
|
||||
for (int i = 1; i <= n; i++) tmp[i] = x[y[i]];
|
||||
Sort(tmp, sa, n, m);
|
||||
for (int i = 1; i <= n; i++) sa[i] = y[sa[i]];
|
||||
swap(x, y);
|
||||
x[sa[1]] = p = 1;
|
||||
for (int i = 2; i <= n; i++)
|
||||
{
|
||||
if (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j]) x[sa[i]] = p;
|
||||
else x[sa[i]] = ++p;
|
||||
}
|
||||
}
|
||||
sa[0] = n + 1; // for calculate height.
|
||||
}
|
||||
int rank[MAXN];
|
||||
inline void getHeight(int ch[], int sa[], int height[], int n)
|
||||
{
|
||||
for (int i = 1; i <= n; i++) rank[sa[i]] = i;
|
||||
for (int i = 1, t = 0; i <= n; i++)
|
||||
{
|
||||
if (t > 0) t--;
|
||||
while (ch[i + t] == ch[sa[rank[i] - 1] + t]) t++;
|
||||
height[rank[i]] = t;
|
||||
}
|
||||
}
|
||||
|
||||
构建后缀自动机。统计一个串出现的次数时,只需统计其节点所对应的子树中,end为true的节点的个数即可。将所有节点按val值从小到大排序后即可得到parent树由根开始的BFS序。
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node *next[26], *par;
|
||||
int val, end; // 26 is volatile
|
||||
} POOL[MAXN << 1], *data, *root, *last; //Note that the size of POOL should be doubled.
|
||||
inline void Add(int x)
|
||||
{
|
||||
Node *p = last, *np = data++;
|
||||
np->val = p->val + 1;
|
||||
np->end = true;
|
||||
while (p && !p->next[x])
|
||||
p->next[x] = np, p = p->par;
|
||||
if (p == 0)
|
||||
{
|
||||
np->par = root;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *q = p->next[x];
|
||||
if (q->val == p->val + 1)
|
||||
{
|
||||
np->par = q;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *nq = data++;
|
||||
nq->val = p->val + 1;
|
||||
memcpy(nq->next, q->next, sizeof q->next);
|
||||
nq->par = q->par;
|
||||
np->par = q->par = nq;
|
||||
while (p && p->next[x] == q)
|
||||
p->next[x] = nq, p = p->par;
|
||||
}
|
||||
}
|
||||
last = np;
|
||||
}
|
||||
void Clear(void)
|
||||
{
|
||||
data = POOL;
|
||||
last = root = data++;
|
||||
}
|
||||
|
825
.ACM-Templates/TXTs/数论模板.txt
Normal file
825
.ACM-Templates/TXTs/数论模板.txt
Normal file
|
@ -0,0 +1,825 @@
|
|||
===============数学方面模板===========
|
||||
计算几何模板,包含:
|
||||
\begin{itemize}
|
||||
\item point2/3 点/向量,方法:向量加+减-,数乘*,点乘*,叉乘%,模dis,辐角arg(2维),旋转rotate(2维),平行parallel,垂直perpend,三维点根据所在面的法向量和一个面上向量投影为二维点以及反投影
|
||||
\item line2/3 线,表示为起点+方向向量,方法:点线距和垂足,线线交、线段线段交(线段交可退化,2维),线线距和最近点对(3维,若平行返回任意一对),线的投影(同点)
|
||||
\item face3 面,表示为起点+法向量,方法:点面距和垂足,线面交,面面交
|
||||
\item circle2 圆,表示为圆心+半径,方法:线圆交,圆圆交,点到圆的切点,圆与圆的公切线(若公切线有两个切点,返回直线两端点为两切点,否则返回直线端点为切点)
|
||||
\item convex2 凸包,方法:面积,点不严格在凸包内,线与凸包交,水平序Graham求凸包,半平面交(半平面为传入向量左侧平面)
|
||||
\end{itemize}
|
||||
说明:对需要求点/线的,点/线作为指针传入,若为NULL表示不需要(默认);对需要求点/线个数的,返回值为-1表示有无穷多个。
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
const double eps = 1e-13;
|
||||
const double pi = 3.14159265358979324;
|
||||
struct point2
|
||||
{
|
||||
double x, y;
|
||||
point2& operator += (point2 a)
|
||||
{
|
||||
x+=a.x, y+=a.y;
|
||||
return *this;
|
||||
}
|
||||
point2& operator -= (point2 a)
|
||||
{
|
||||
x-=a.x, y-=a.y;
|
||||
return *this;
|
||||
}
|
||||
point2& operator *= (double a)
|
||||
{
|
||||
x*=a, y*=a;
|
||||
return *this;
|
||||
}
|
||||
point2& operator /= (double a)
|
||||
{
|
||||
x/=a, y/=a;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
point2 operator + (point2 a, point2 b)
|
||||
{
|
||||
point2 c(a);
|
||||
c += b;
|
||||
return c;
|
||||
}
|
||||
point2 operator - (point2 a, point2 b)
|
||||
{
|
||||
point2 c(a);
|
||||
c -= b;
|
||||
return c;
|
||||
}
|
||||
point2 operator * (point2 a, double b)
|
||||
{
|
||||
point2 c(a);
|
||||
c *= b;
|
||||
return c;
|
||||
}
|
||||
point2 operator * (double a, point2 b)
|
||||
{
|
||||
point2 c(b);
|
||||
c *= a;
|
||||
return c;
|
||||
}
|
||||
point2 operator / (point2 a, double b)
|
||||
{
|
||||
point2 c(a);
|
||||
c /= b;
|
||||
return c;
|
||||
}
|
||||
double operator * (point2 a, point2 b)
|
||||
{
|
||||
return a.x*b.x+a.y*b.y;
|
||||
}
|
||||
double operator % (point2 a, point2 b)
|
||||
{
|
||||
return a.x*b.y-a.y*b.x;
|
||||
}
|
||||
double dis(point2 a)
|
||||
{
|
||||
return sqrt(a.x * a.x + a.y * a.y);
|
||||
}
|
||||
double arg(point2 a)
|
||||
{
|
||||
return atan2(a.y, a.x);
|
||||
}
|
||||
point2 rotate(point2 a, double th)
|
||||
{
|
||||
point2 b;
|
||||
b.x = a.x * cos(th) - a.y * sin(th);
|
||||
b.y = a.x * sin(th) + a.y * cos(th);
|
||||
return b;
|
||||
}
|
||||
int parallel(point2 a, point2 b)
|
||||
{
|
||||
return a * a < eps * eps || b * b < eps * eps
|
||||
|| (a % b) * (a % b) / ((a * a) * (b * b)) < eps * eps;
|
||||
}
|
||||
int perpend(point2 a, point2 b)
|
||||
{
|
||||
return a * a < eps * eps || b * b < eps * eps
|
||||
|| (a * b) * (a * b) / ((a * a) * (b * b)) < eps * eps;
|
||||
}
|
||||
struct line2
|
||||
{
|
||||
point2 a, s;
|
||||
};
|
||||
struct circle2
|
||||
{
|
||||
point2 a;
|
||||
double r;
|
||||
};
|
||||
double point_line_dis(point2 a, line2 b, point2 *res = NULL)
|
||||
{
|
||||
point2 p;
|
||||
p = b.a + ((a - b.a) * b.s) / (b.s * b.s) * b.s;
|
||||
if (res != NULL) *res = p;
|
||||
return dis(a - p);
|
||||
}
|
||||
int line_line_cross(line2 a, line2 b, point2 *res = NULL)
|
||||
{
|
||||
if (parallel(a.s, b.s))
|
||||
if (parallel(b.a - a.a, a.s))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
double k1 = (b.a - a.a) % b.s / (a.s % b.s);
|
||||
if (res != NULL) *res = a.a + k1 * a.s;
|
||||
return 1;
|
||||
}
|
||||
int segment_segment_cross(line2 a, line2 b, point2 *res = NULL)
|
||||
{
|
||||
if (a.s * a.s < eps * eps && b.s * b.s < eps * eps)
|
||||
if ((b.a - a.a) * (b.a - a.a) < eps * eps)
|
||||
{
|
||||
if (res != NULL) *res = a.a;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
if (parallel(a.s, b.s) && parallel(b.a - a.a, a.s) && parallel(a.a - b.a, b.s))
|
||||
{
|
||||
double y1, y2, y3, y4;
|
||||
point2 y1p = a.a, y2p = a.a + a.s, y3p = b.a, y4p = b.a + b.s;
|
||||
if (std::abs(a.s.x) < std::abs(a.s.y) || std::abs(b.s.x) < std::abs(b.s.y))
|
||||
y1 = y1p.y, y2 = y2p.y, y3 = y3p.y, y4 = y4p.y;
|
||||
else
|
||||
y1 = y1p.x, y2 = y2p.x, y3 = y3p.x, y4 = y4p.x;
|
||||
if (y1 > y2) std::swap(y1, y2), std::swap(y1p, y2p);
|
||||
if (y3 > y4) std::swap(y3, y4), std::swap(y3p, y4p);
|
||||
if (y2 - y1 < y4 - y3) std::swap(y1, y3), std::swap(y1p, y3p), std::swap(y2, y4), std::swap(y2p, y4p);
|
||||
if (y3 > y2 + (y2 - y1) * eps || y4 < y1 - (y2 - y1) * eps)
|
||||
return 0;
|
||||
else if (fabs(y3 - y2) < (y2 - y1) * eps || fabs(y3 - y4) < eps)
|
||||
{
|
||||
if (res != NULL) *res = y3p;
|
||||
return 1;
|
||||
}
|
||||
else if (fabs(y4 - y1) < (y2 - y1) * eps || fabs(y1 - y2) < eps)
|
||||
{
|
||||
if (res != NULL) *res = y1p;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
double k1 = (b.a - a.a) % a.s, k2 = (b.a + b.s - a.a) % a.s;
|
||||
k1 /= a.s * a.s, k2 /= a.s * a.s;
|
||||
double k3 = (a.a - b.a) % b.s, k4 = (a.a + a.s - b.a) % b.s;
|
||||
k3 /= b.s * b.s, k4 /= b.s * b.s;
|
||||
int ret = (k1 < eps && k2 > -eps || k1 > -eps && k2 < eps)
|
||||
&& (k3 < eps && k4 > -eps || k3 > -eps && k4 < eps);
|
||||
if (ret) line_line_cross(a, b, res);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
int line_circle_cross(line2 a, circle2 b, point2 *res1 = NULL, point2 *res2 = NULL)
|
||||
{
|
||||
point2 p;
|
||||
double d = point_line_dis(b.a, a, &p);
|
||||
if (d / b.r > 1 + eps)
|
||||
return 0;
|
||||
else if (d / b.r > 1 - eps)
|
||||
{
|
||||
if (res1 != NULL) *res1 = p;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = sqrt(b.r * b.r - d * d) / dis(a.s);
|
||||
if (res1 != NULL) *res1 = p + d * a.s;
|
||||
if (res2 != NULL) *res2 = p - d * a.s;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int circle_circle_cross(circle2 a, circle2 b, point2 *res1 = NULL, point2 *res2 = NULL)
|
||||
{
|
||||
double d = dis(a.a - b.a);
|
||||
point2 u = (b.a - a.a) / d;
|
||||
if (d / (a.r + b.r) > 1 + eps)
|
||||
return 0;
|
||||
else if (d / (a.r + b.r) > 1 - eps)
|
||||
{
|
||||
if (res1 != NULL) *res1 = a.a + u * a.r;
|
||||
return 1;
|
||||
}
|
||||
else if ((d - fabs(a.r - b.r)) / (a.r + b.r) > eps)
|
||||
{
|
||||
double th = acos((a.r * a.r + d * d - b.r * b.r) / (2 * a.r * d));
|
||||
if (res1 != NULL) *res1 = a.a + rotate(u * a.r, th);
|
||||
if (res2 != NULL) *res2 = a.a + rotate(u * a.r, -th);
|
||||
return 2;
|
||||
}
|
||||
else if ((d - fabs(a.r - b.r)) / (a.r + b.r) > -eps)
|
||||
{
|
||||
if (a.r / b.r < 1 - eps)
|
||||
{
|
||||
if (res1 != NULL) *res1 = b.a - u * b.r;
|
||||
return 1;
|
||||
}
|
||||
else if (a.r / b.r > 1 + eps)
|
||||
{
|
||||
if (res1 != NULL) *res1 = a.a + u * a.r;
|
||||
return 1;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
int point_circle_tangent(point2 a, circle2 b, point2 *res1 = NULL, point2 *res2 = NULL)
|
||||
{
|
||||
double d = dis(a - b.a);
|
||||
point2 u = (a - b.a) / d;
|
||||
if (d / b.r > 1 + eps)
|
||||
{
|
||||
double th = acos(b.r / d);
|
||||
if (res1 != NULL) *res1 = b.a + rotate(u * b.r, th);
|
||||
if (res2 != NULL) *res2 = b.a + rotate(u * b.r, -th);
|
||||
return 2;
|
||||
}
|
||||
else if (d / b.r > 1 - eps)
|
||||
{
|
||||
if (res1 != NULL) *res1 = a;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
int circle_circle_tangent(circle2 a, circle2 b, line2 *reso1 = NULL, line2 *reso2 = NULL, line2 *resi1 = NULL, line2 *resi2 = NULL)
|
||||
{
|
||||
double d = dis(a.a - b.a);
|
||||
point2 u = (b.a - a.a) / d;
|
||||
int cnt = 0;
|
||||
if ((d - fabs(a.r - b.r)) / (a.r + b.r) > eps)
|
||||
{
|
||||
double th = acos((a.r - b.r) / d);
|
||||
if (reso1 != NULL)
|
||||
{
|
||||
reso1->a = a.a + rotate(u * a.r, th);
|
||||
reso1->s = b.a + rotate(u * b.r, th) - reso1->a;
|
||||
}
|
||||
if (reso2 != NULL)
|
||||
{
|
||||
reso2->a = a.a + rotate(u * a.r, -th);
|
||||
reso2->s = b.a + rotate(u * b.r, -th) - reso2->a;
|
||||
}
|
||||
cnt += 2;
|
||||
}
|
||||
else if ((d - fabs(a.r - b.r)) / (a.r + b.r) > -eps)
|
||||
{
|
||||
if (a.r / b.r < 1 - eps)
|
||||
{
|
||||
if (reso1 != NULL)
|
||||
{
|
||||
reso1->a = b.a - u * b.r;
|
||||
reso1->s = rotate(u, pi / 2);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
else if (a.r / b.r > 1 + eps)
|
||||
{
|
||||
if (reso1 != NULL)
|
||||
{
|
||||
reso1->a = a.a + u * a.r;
|
||||
reso1->s = rotate(u, pi / 2);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
if (d / (a.r + b.r) > 1 + eps)
|
||||
{
|
||||
double th = acos((a.r + b.r) / d);
|
||||
if (resi1 != NULL)
|
||||
{
|
||||
resi1->a = a.a + rotate(u * a.r, th);
|
||||
resi1->s = b.a - rotate(u * b.r, th) - resi1->a;
|
||||
}
|
||||
if (resi2 != NULL)
|
||||
{
|
||||
resi2->a = a.a + rotate(u * a.r, -th);
|
||||
resi2->s = b.a - rotate(u * b.r, -th) - resi2->a;
|
||||
}
|
||||
cnt += 2;
|
||||
}
|
||||
else if (d / (a.r + b.r) > 1 - eps)
|
||||
{
|
||||
if (resi1 != NULL)
|
||||
{
|
||||
resi1->a = a.a + u * a.r;
|
||||
resi1->s = rotate(u, pi / 2);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
typedef std::vector<point2> convex2;
|
||||
double area(const convex2 &a)
|
||||
{
|
||||
double s = 0;
|
||||
for (int i = 0; i < a.size(); i++)
|
||||
s += a[i] % a[(i+1)%a.size()];
|
||||
return fabs(s)/2;
|
||||
}
|
||||
int point_convex_inside(point2 a, const convex2 &b)
|
||||
{
|
||||
double sum = 0;
|
||||
for (int i = 0; i < b.size(); i++)
|
||||
sum += fabs((b[i] - a) % (b[(i+1)%b.size()] - a));
|
||||
return fabs(sum / (2*area(b)) - 1) < eps;
|
||||
}
|
||||
int line_convex_cross(line2 a, const convex2 &b, point2 *res1 = NULL, point2 *res2 = NULL)
|
||||
{
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < b.size(); i++)
|
||||
{
|
||||
line2 ltmp;
|
||||
point2 ptmp;
|
||||
ltmp.a = b[i], ltmp.s = b[(i+1)%b.size()] - b[i];
|
||||
int flag = line_line_cross(a, ltmp, &ptmp);
|
||||
if (flag == -1) return -1;
|
||||
if (flag == 0) continue;
|
||||
double k = (ptmp - ltmp.a) * ltmp.s / (ltmp.s * ltmp.s);
|
||||
if (k < eps || k > 1+eps) continue;
|
||||
if (cnt == 0 && res1 != NULL) *res1 = ptmp;
|
||||
else if (cnt == 1 && res2 != NULL) *res2 = ptmp;
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
int convex_gen_cmp(point2 a, point2 b)
|
||||
{
|
||||
return a.y < b.y - eps || fabs(a.y - b.y) < eps && a.x < b.x - eps;
|
||||
}
|
||||
int convex_gen(const convex2 &a, convex2 &b)
|
||||
{
|
||||
std::deque<point2> q;
|
||||
convex2 t(a);
|
||||
std::sort(t.begin(), t.end(), convex_gen_cmp);
|
||||
q.push_back(t[0]), q.push_back(t[1]);
|
||||
for (int i = 2; i < t.size(); i++)
|
||||
{
|
||||
while (q.size() > 1)
|
||||
{
|
||||
point2 p1 = t[i]-q[q.size()-1], p2 = q[q.size()-1]-q[q.size()-2];
|
||||
if (p1 % p2 > 0 || parallel(p1, p2)) q.pop_back();
|
||||
else break;
|
||||
}
|
||||
q.push_back(t[i]);
|
||||
}
|
||||
int pretop = q.size();
|
||||
for (int i = t.size()-1; i >= 0; i--)
|
||||
{
|
||||
while (q.size() > pretop)
|
||||
{
|
||||
point2 p1 = t[i]-q[q.size()-1], p2 = q[q.size()-1]-q[q.size()-2];
|
||||
if (p1 % p2 > 0 || parallel(p1, p2)) q.pop_back();
|
||||
else break;
|
||||
}
|
||||
q.push_back(t[i]);
|
||||
}
|
||||
q.pop_back();
|
||||
if (q.size() < 3)
|
||||
{
|
||||
b.clear();
|
||||
return 0;
|
||||
}
|
||||
b.clear();
|
||||
for (int i = 0; i < q.size(); i++) b.push_back(q[i]);
|
||||
return 1;
|
||||
}
|
||||
int halfplane_cross_cmp(line2 a, line2 b)
|
||||
{
|
||||
double c1 = arg(a.s), c2 = arg(b.s);
|
||||
return c1 < c2-eps || fabs(c1-c2) < eps && b.s % (a.a - b.a) / dis(b.s) > eps;
|
||||
}
|
||||
int halfplane_cross(const std::vector<line2> &a, convex2 &b)
|
||||
{
|
||||
std::vector<line2> t(a);
|
||||
std::sort(t.begin(), t.end(), halfplane_cross_cmp);
|
||||
int j = 0;
|
||||
for (int i = 0; i < t.size(); i++)
|
||||
if (!i || arg(t[i].s) > arg(t[i-1].s) + eps) t[j++] = t[i];
|
||||
if (j > 0 && arg(t[j].s) > arg(t[0].s) + 2*pi - eps) j--;
|
||||
t.resize(j);
|
||||
std::deque<line2> q;
|
||||
q.push_back(t[0]), q.push_back(t[1]);
|
||||
point2 p;
|
||||
for (int i = 2, k = 0; i < t.size(); i++)
|
||||
{
|
||||
for (; k < q.size() && t[i].s % q[k].s > 0; k++);
|
||||
point2 s1 = q[q.size()-1].s, s2 = q[0].s;
|
||||
if (k > 0 && k < q.size() && s1 % s2 > 0 && !parallel(s1, s2))
|
||||
{
|
||||
line_line_cross(q[k], q[k-1], &p);
|
||||
double r1 = t[i].s % (p - t[i].a) / dis(t[i].s);
|
||||
line_line_cross(q[0], q[q.size()-1], &p);
|
||||
double r2 = t[i].s % (p - t[i].a) / dis(t[i].s);
|
||||
if (r1 < eps && r2 < eps)
|
||||
{
|
||||
b.clear();
|
||||
return 0;
|
||||
}
|
||||
else if (r1 > -eps && r2 > -eps)
|
||||
continue;
|
||||
}
|
||||
while (q.size() > 1)
|
||||
{
|
||||
line_line_cross(q[q.size()-1], q[q.size()-2], &p);
|
||||
if (t[i].s % (p - t[i].a) / dis(t[i].s) < eps)
|
||||
{
|
||||
q.pop_back();
|
||||
if (k == q.size()) k--;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
while (q.size() > 1)
|
||||
{
|
||||
line_line_cross(q[0], q[1], &p);
|
||||
if (t[i].s % (p - t[i].a) / dis(t[i].s) < eps)
|
||||
{
|
||||
q.pop_front();
|
||||
k--;
|
||||
if (k < 0) k = 0;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
q.push_back(t[i]);
|
||||
}
|
||||
b.clear();
|
||||
for (int i = 0; i < q.size(); i++)
|
||||
{
|
||||
line_line_cross(q[i], q[(i+1)%q.size()], &p);
|
||||
b.push_back(p);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
struct point3
|
||||
{
|
||||
double x, y, z;
|
||||
point3& operator += (point3 a)
|
||||
{
|
||||
x+=a.x,y+=a.y,z+=a.z;
|
||||
return *this;
|
||||
}
|
||||
point3& operator -= (point3 a)
|
||||
{
|
||||
x-=a.x,y-=a.y,z-=a.z;
|
||||
return *this;
|
||||
}
|
||||
point3& operator *= (double a)
|
||||
{
|
||||
x*=a, y*=a, z*=a;
|
||||
return *this;
|
||||
}
|
||||
point3& operator /= (double a)
|
||||
{
|
||||
x/=a, y/=a, z/=a;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
point3 operator + (point3 a, point3 b)
|
||||
{
|
||||
point3 c(a);
|
||||
c += b;
|
||||
return c;
|
||||
}
|
||||
point3 operator - (point3 a, point3 b)
|
||||
{
|
||||
point3 c(a);
|
||||
c -= b;
|
||||
return c;
|
||||
}
|
||||
point3 operator * (point3 a, double b)
|
||||
{
|
||||
point3 c(a);
|
||||
c *= b;
|
||||
return c;
|
||||
}
|
||||
point3 operator * (double a, point3 b)
|
||||
{
|
||||
point3 c(b);
|
||||
c *= a;
|
||||
return c;
|
||||
}
|
||||
point3 operator / (point3 a, double b)
|
||||
{
|
||||
point3 c(a);
|
||||
c /= b;
|
||||
return c;
|
||||
}
|
||||
double operator * (point3 a, point3 b)
|
||||
{
|
||||
return a.x*b.x+a.y*b.y+a.z*b.z;
|
||||
}
|
||||
point3 operator % (point3 a, point3 b)
|
||||
{
|
||||
point3 c;
|
||||
c.x = a.y * b.z - a.z * b.y;
|
||||
c.y = a.z * b.x - a.x * b.z;
|
||||
c.z = a.x * b.y - a.y * b.x;
|
||||
return c;
|
||||
}
|
||||
double dis(point3 a)
|
||||
{
|
||||
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
|
||||
}
|
||||
int parallel(point3 a, point3 b)
|
||||
{
|
||||
return a * a < eps * eps || b * b < eps * eps
|
||||
|| (a % b) * (a % b) / ((a * a) * (b * b)) < eps * eps;
|
||||
}
|
||||
int perpend(point3 a, point3 b)
|
||||
{
|
||||
return a * a < eps * eps || b * b < eps * eps
|
||||
|| (a * b) * (a * b) / ((a * a) * (b * b)) < eps * eps;
|
||||
}
|
||||
struct line3
|
||||
{
|
||||
point3 a, s;
|
||||
};
|
||||
struct face3
|
||||
{
|
||||
point3 a, n;
|
||||
};
|
||||
struct circle3
|
||||
{
|
||||
point3 a;
|
||||
double r;
|
||||
};
|
||||
point2 project(point3 a, face3 b, point3 xs)
|
||||
{
|
||||
point3 ys;
|
||||
ys = b.n % xs;
|
||||
point2 c;
|
||||
c.x = ((a - b.a) * xs) / dis(xs), c.y = ((a - b.a) * ys) / dis(ys);
|
||||
return c;
|
||||
}
|
||||
line2 project(line3 a, face3 b, point3 xs)
|
||||
{
|
||||
line2 c;
|
||||
c.a = project(a.a, b, xs), c.s = project(a.a + a.s, b, xs) - c.a;
|
||||
return c;
|
||||
}
|
||||
point3 revproject(point2 a, face3 b, point3 xs)
|
||||
{
|
||||
point3 ys;
|
||||
ys = b.n % xs;
|
||||
return a.x * xs / dis(xs) + a.y * ys / dis(ys) + b.a;
|
||||
}
|
||||
line3 revproject(line2 a, face3 b, point3 xs)
|
||||
{
|
||||
line3 c;
|
||||
c.a = revproject(a.a, b, xs), c.s = revproject(a.a + a.s, b, xs) - c.a;
|
||||
return c;
|
||||
}
|
||||
double point_line_dis(point3 a, line3 b, point3 *res = NULL)
|
||||
{
|
||||
point3 p;
|
||||
p = b.a + ((a - b.a) * b.s) / (b.s * b.s) * b.s;
|
||||
if (res != NULL) *res = p;
|
||||
return dis(a - p);
|
||||
}
|
||||
double point_face_dis(point3 a, face3 b, point3 *res = NULL)
|
||||
{
|
||||
point3 p;
|
||||
p = ((a - b.a) * b.n) / (b.n * b.n) * b.n;
|
||||
if (res != NULL) *res = a - p;
|
||||
return dis(p);
|
||||
}
|
||||
double line_line_dis(line3 a, line3 b, point3 *resa = NULL, point3 *resb = NULL)
|
||||
{
|
||||
point3 p;
|
||||
if (parallel(a.s, b.s))
|
||||
{
|
||||
double d = point_line_dis(a.a, b, &p);
|
||||
if (resa != NULL) *resa = a.a;
|
||||
if (resb != NULL) *resb = p;
|
||||
return d;
|
||||
}
|
||||
point3 n = a.s % b.s;
|
||||
face3 f;
|
||||
f.a = b.a, f.n = n;
|
||||
double d = point_face_dis(a.a, f, &p);
|
||||
double k1 = ((b.a - p) % b.s) * n / (n * n);
|
||||
if (resb != NULL) *resb = p + k1 * a.s;
|
||||
if (resa != NULL) *resa = a.a + k1 * a.s;
|
||||
return d;
|
||||
}
|
||||
int line_face_cross(line3 a, face3 b, point3 *res = NULL)
|
||||
{
|
||||
if (perpend(a.s, b.n))
|
||||
if (perpend(b.a - a.a, b.n))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
double k = (b.a - a.a) * b.n / (a.s * b.n);
|
||||
if (res != NULL) *res = a.a + k * a.s;
|
||||
return 1;
|
||||
}
|
||||
int face_face_cross(face3 a, face3 b, line3 *res = NULL)
|
||||
{
|
||||
if (parallel(a.n, b.n))
|
||||
if (perpend(b.a - a.a, a.n))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
point3 s = a.n % b.n;
|
||||
point3 p;
|
||||
line3 t;
|
||||
t.a = a.a, t.s = a.n % s;
|
||||
line_face_cross(t, b, &p);
|
||||
if (res != NULL)
|
||||
res->a = p, res->s = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
=============数论模板==========
|
||||
数论模板,其中包含:
|
||||
\begin{itemize}
|
||||
\item ext\_gcd:扩展欧几里得方法解 $ax+by=\gcd(a,b)$,该函数保证当 $a,b>0$ 时 $x>0$。
|
||||
\item flsum:欧几里得思想解 $\sum_{x=st}^{ed}\lfloor\frac{ax+b}c\rfloor$。
|
||||
\item ind:小步大步走算法求 $a^x=m\pmod b$。
|
||||
\item prepare\_inv:$O(p)$ 求模 $p$ 域下所有非零元的逆元($p$ 素数)。
|
||||
\end{itemize}
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
void ext_gcd(int a, int b, int &x, int &y)
|
||||
{
|
||||
if (!b) x = 1, y = 0;
|
||||
else if (!a) x = 1, y = -1;
|
||||
else if (a > b) ext_gcd(a % b, b, x, y), y += a / b * x;
|
||||
else ext_gcd(a, b % a, x, y), x += b / a * y;
|
||||
}
|
||||
long long flsum_t (long long a, long long b, long long c, long long n)
|
||||
{
|
||||
if (n < 0) return 0;
|
||||
if (c < 0) a = -a, b = -b, c = -c;
|
||||
n++;
|
||||
long long res = 0;
|
||||
if (a < 0 || a >= c)
|
||||
{
|
||||
long long ra = (a % c + c) % c;
|
||||
long long k = (a - ra) / c;
|
||||
res += k * n * (n - 1) / 2;
|
||||
a = ra;
|
||||
}
|
||||
if (b < 0 || b >= c)
|
||||
{
|
||||
long long rb = (b % c + c) % c;
|
||||
long long k = (b - rb) / c;
|
||||
res += k * n;
|
||||
b = rb;
|
||||
}
|
||||
if (a * n + b < c) return res;
|
||||
else return res + flsum_t(c, (a * n + b) % c, a, (a * n + b) / c - 1);
|
||||
}
|
||||
long long flsum (long long a, long long b, long long c, long long st, long long ed)
|
||||
{
|
||||
return flsum_t(a, b, c, ed) - flsum_t(a, b, c, st - 1);
|
||||
}
|
||||
int power(int n, int k, int r)
|
||||
{
|
||||
int t = n, s = 1;
|
||||
for (; k; k >>= 1, t = 1LL * t * t % r)
|
||||
if (k & 1) s = 1LL * s * t % r;
|
||||
return s;
|
||||
}
|
||||
int millerrabin(int x, int tester)
|
||||
{
|
||||
int k = x-1;
|
||||
for (; !(k & 1); k >>= 1);
|
||||
int y = power(tester, k, x);
|
||||
if (y == 1) return 1;
|
||||
for (; k < x-1; k <<= 1, y = 1LL * y * y % x)
|
||||
if (y == x-1) return 1;
|
||||
return 0;
|
||||
}
|
||||
int isprime(int x)
|
||||
{
|
||||
if (x == 2 || x == 7 || x == 61) return 1;
|
||||
return millerrabin(x, 2) && millerrabin(x, 7) && millerrabin(x, 61);
|
||||
}
|
||||
int rho_f(int x, int c, int p)
|
||||
{
|
||||
return (1LL * x * x + c) % p;
|
||||
}
|
||||
int rho(int n)
|
||||
{
|
||||
int c = rand() % (n-1) + 1, x = 2, y = x, d = 1;
|
||||
while (d == 1)
|
||||
{
|
||||
x = rho_f(x, c, n);
|
||||
y = rho_f(rho_f(y, c, n), c, n);
|
||||
d = std::__gcd(y > x ? y-x : x-y, n);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
void factor(int n, std::vector<int> &res)
|
||||
{
|
||||
if (n == 1) return;
|
||||
else if (isprime(n)) res.push_back(n);
|
||||
else if (n == 4) res.push_back(2), res.push_back(2);
|
||||
else
|
||||
{
|
||||
int d;
|
||||
while ((d = rho(n)) == n);
|
||||
factor(d, res), factor(n / d, res);
|
||||
}
|
||||
}
|
||||
int ind(int a, int b, int m)
|
||||
{
|
||||
a %= m, b %= m;
|
||||
std::map<int, int> hash;
|
||||
int r = (int)(sqrt(m)), k = 1;
|
||||
if (r * r < m) r++;
|
||||
for (int i = 0; i < r; i++, k = 1LL * k * a % m)
|
||||
if (hash.find(k) == hash.end())
|
||||
hash.insert(std::make_pair(k, i));
|
||||
int s = 1;
|
||||
std::map<int, int>::iterator it;
|
||||
for (int i = 0; i < r; i++, s = 1LL * s * k % m)
|
||||
{
|
||||
int x, y, t;
|
||||
ext_gcd(s, m, x, y);
|
||||
t = 1LL * b * x % m;
|
||||
if ((it = hash.find(t)) != hash.end())
|
||||
return i * r + it->second;
|
||||
}
|
||||
}
|
||||
void prepare_inv(int *inv, int p)
|
||||
{
|
||||
inv[1] = 1;
|
||||
for (int i = 2; i < p; i++)
|
||||
inv[i] = 1LL * inv[p%i] * (p - p/i) % p;
|
||||
}
|
||||
|
||||
|
||||
=================数值计算=============
|
||||
数值计算模板,内含:
|
||||
\begin{itemize}
|
||||
\item area\_simpson:Simpson法求定积分。
|
||||
\item fft\_prepare:求 $maxn$ 次单位根,包括负指数。
|
||||
\item dft:做长度为 $N(N|maxn)$ 的DFT,其中若 $f=-1$ 则求IDFT。
|
||||
\end{itemize}
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
const double pi = 3.14159265358979324;
|
||||
typedef double (*__F) (double);
|
||||
double area(double x, double y, double fl, double fmid, double fr)
|
||||
{
|
||||
return (fl + 4 * fmid + fr) * (y - x) / 6;
|
||||
}
|
||||
double area_simpson_solve(__F f, double x, double mid, double y, double fl, double fmid, double fr, double pre, double zero)
|
||||
{
|
||||
double lmid = (x + mid) / 2, rmid = (mid + y) / 2;
|
||||
double flmid = f(lmid), frmid = f(rmid);
|
||||
double al = area(x, mid, fl, flmid, fmid), ar = area(mid, y, fmid, frmid, fr);
|
||||
if (fabs(al + ar - pre) < zero) return al + ar;
|
||||
else return area_simpson_solve(f, x, lmid, mid, fl, flmid, fmid, al, zero) + area_simpson_solve(f, mid, rmid, y, fmid, frmid, fr, ar, zero);
|
||||
}
|
||||
double area_simpson(__F f, double x, double y, double zero = 1e-10)
|
||||
{
|
||||
double mid = (x + y) / 2, fl = f(x), fmid = f(mid), fr = f(y);
|
||||
return area_simpson_solve(f, x, mid, y, fl, fmid, fr, area(x, y, fl, fmid, fr), zero);
|
||||
}
|
||||
typedef std::complex<double> complex;
|
||||
void fft_prepare(int maxn, complex *&e)
|
||||
{
|
||||
e = new complex[2 * maxn - 1];
|
||||
e += maxn - 1;
|
||||
e[0] = complex(1, 0);
|
||||
for (int i = 1; i < maxn; i <<= 1)
|
||||
e[i] = complex(cos(2 * pi * i / maxn), sin(2 * pi * i / maxn));
|
||||
for (int i = 3; i < maxn; i++)
|
||||
if ((i & -i) != i) e[i] = e[i - (i & -i)] * e[i & -i];
|
||||
for (int i = 1; i < maxn; i++) e[-i] = e[maxn - i];
|
||||
}
|
||||
/* f = 1: dft; f = -1: idft */
|
||||
void dft(complex *a, int N, int f, complex *e, int maxn)
|
||||
{
|
||||
int d = maxn / N * f;
|
||||
complex x;
|
||||
for (int n = N, m; m = n / 2, m >= 1; n = m, d *= 2)
|
||||
for (int i = 0; i < m; i++)
|
||||
for (int j = i; j < N; j += n)
|
||||
x = a[j] - a[j+m], a[j] += a[j+m], a[j+m] = x * e[d * i];
|
||||
for (int i = 0, j = 1; j < N - 1; j++)
|
||||
{
|
||||
for (int k = N / 2; k > (i ^= k); k /= 2);
|
||||
if (j < i) std::swap(a[i], a[j]);
|
||||
}
|
||||
}
|
47
.ACM-Templates/TXTs/日期.txt
Normal file
47
.ACM-Templates/TXTs/日期.txt
Normal file
|
@ -0,0 +1,47 @@
|
|||
//日期函数
|
||||
char *week[] = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"};
|
||||
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
struct Date { int y, m, d; };
|
||||
//判闰年
|
||||
inline int leap(int y) {
|
||||
return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
|
||||
}
|
||||
//判合法性
|
||||
inline bool legal(Date &a) {
|
||||
if (a.m < 0 || a.m > 12) { return false; }
|
||||
if (a.m == 2) { return a.d > 0 && a.d <= 28 + leap(a.y); }
|
||||
return a.d > 0 && a.d <= days[a.m - 1];
|
||||
}
|
||||
//比较日期大小
|
||||
inline int datecmp(Date &a, Date &b) {
|
||||
if (a.y != b.y) { return a.y - b.y; }
|
||||
if (a.m != b.m) { return a.m - b.m; }
|
||||
return a.d - b.d;
|
||||
}
|
||||
//返回指定日期是星期几
|
||||
int DaysOfTheWeek(Date a) {
|
||||
if (a.m == 1 || a.m == 2) { a.m += 12; a.y--; } //1月2月当作前一年的13, 14月
|
||||
//判断是否在1752年9月3日之前
|
||||
if (a.y < 1752 || (a.y == 1752 && a.m < 9) || (a.y == 1752 && a.m == 9 && a.d < 3)) {
|
||||
return (a.d + 2 * a.m + 3 * (a.m + 1) / 5 + a.y + a.y / 4 + 5) % 7;
|
||||
} else {
|
||||
return (a.d + 2 * a.m + 3 * (a.m + 1) / 5 + a.y + a.y / 4 - a.y / 100 + a.y / 400) % 7;
|
||||
}
|
||||
}
|
||||
//日期转天数偏移
|
||||
int date2int(Date a) {
|
||||
int ret = a.y * 365 + (a.y - 1) / 4 - (a.y - 1) / 100 + (a.y - 1) / 400;
|
||||
days[1] += leap(a.y);
|
||||
for (int i = 0; i < a.m - 1; ret += days[i++]);
|
||||
days[1] = 28;
|
||||
return ret + a.d;
|
||||
}
|
||||
//天数偏移转日期
|
||||
Date int2date(int a) {
|
||||
Date ret; ret.y = a / 146097 * 400;
|
||||
for (a %= 146097; a >= 365 + leap(ret.y); a -= 365 + leap(ret.y), ret.y++);
|
||||
days[1] += leap(ret.y);
|
||||
for (ret.m = 1; a >= days[ret.m - 1]; a -= days[ret.m - 1], ret.m++);
|
||||
days[1] = 28; ret.d = a + 1;
|
||||
return ret;
|
||||
}
|
772
.ACM-Templates/TXTs/混合模板.txt
Normal file
772
.ACM-Templates/TXTs/混合模板.txt
Normal file
|
@ -0,0 +1,772 @@
|
|||
==================混合模板组================
|
||||
|
||||
============手速模板(全)==============
|
||||
#if __cplusplus >= 201103L
|
||||
#include <bits/stdc++.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
typedef long long ll;
|
||||
const int N = 100005;
|
||||
const int M = 1000000007;
|
||||
|
||||
int n, m;
|
||||
int a[N];
|
||||
|
||||
int main() {
|
||||
int C = 0, T;
|
||||
scanf("%d", &T);
|
||||
while (++C <= T) {
|
||||
scanf("%d", &n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
scanf("%d", &a[i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
===============手速模板(最小)===============
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
typedef long long ll;
|
||||
const int N = 100005;
|
||||
const int M = 1000000007;
|
||||
|
||||
int n, m;
|
||||
int a[N];
|
||||
|
||||
int main() {
|
||||
while (~scanf("%d", &n)) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
scanf("%d", &a[i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=============博弈==================
|
||||
//威佐夫博弈 Wizov game
|
||||
//有两堆各若干个物品, 两个人轮流从某一堆或同时从两堆中取同样多的物品, 规定每次至少取一个, 多者不限, 最后取光者得胜
|
||||
//ak = [k(1 + √ 5) / 2], bk = ak + k (k = 0, 1, 2, ..., n 方括号表示取整函数)
|
||||
const double gs = (sqrt(5.0) + 1.0) / 2.0;
|
||||
bool Wizov(ll a, ll b) {
|
||||
return min(a, b) == (ll)(abs(a - b) * gs);
|
||||
}
|
||||
//威佐夫博弈 1 <= N <= 1e18
|
||||
const int N = 95; //~95 for 1e18
|
||||
ll fib[N] = { 0, 1 }; //预处理fibonacci数列
|
||||
bool s[N];
|
||||
bool Wizov(ll a, ll b) {
|
||||
int w = upper_bound(fib + 1, fib + N, a) - fib - 1, pos = 1; ll ret = 0;
|
||||
for (int i = w; i > 0; i--) {
|
||||
if (a >= fib[i]) { s[i] = true; a -= fib[i]; }
|
||||
else { s[i] = false; }
|
||||
}
|
||||
while (!s[pos]) { pos++; }
|
||||
for (int i = pos & 1 ? w - 2 : w; i >= 0; i--) {
|
||||
if (s[i]) { ret += fib[i + 1]; }
|
||||
}
|
||||
return ret == b;
|
||||
}
|
||||
//尼姆博奕 Nimm Game
|
||||
//有三堆各若干个物品, 两个人轮流从某一堆取任意多的物品, 规定每次至少取一个, 多者不限, 最后取光者得胜
|
||||
//计算从1 - n范围内的SG值
|
||||
//Array存储可以走的步数, Array[0]表示可以有多少种走法
|
||||
//Array[]需要从小到大排序
|
||||
//HDU1847 博弈SG函数
|
||||
//1.可选步数为1-m的连续整数,直接取模即可,SG(x) = x % (m + 1); (即巴什博奕 Bash game)
|
||||
//2.可选步数为任意步,SG(x) = x;
|
||||
//3.可选步数为一系列不连续的数,用SG(x)计算
|
||||
int sg[N];
|
||||
bool Hash[N];
|
||||
int SG(int Array[], int n) {
|
||||
memset(sg, 0, sizeof(sg));
|
||||
for (int i = 0; i <= n; ++i) {
|
||||
memset(Hash, 0, sizeof(Hash));
|
||||
for (int j = 1; j <= Array[0]; j++) {
|
||||
if (i < Array[j]) { break; }
|
||||
Hash[sg[i - Array[j]]] = true;
|
||||
}
|
||||
for (int j = 0; j <= n; j++) {
|
||||
if (!Hash[j]) { sg[i] = j; break; }
|
||||
}
|
||||
}
|
||||
return sg[n];
|
||||
}
|
||||
//带输出方案
|
||||
int a[N], ans[N][2]; //a[]为各堆石子数量
|
||||
void printNim(int n) { //石子堆数
|
||||
int cnt = 0, ret = 0;
|
||||
for (int i = 0; i < n; i++) { ret ^= a[i]; }
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (a[i] > (ret ^ a[i])) {
|
||||
ans[cnt][0] = a[i]; ans[cnt][1] = s ^ a[i];
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt) { //判断先手是胜是负
|
||||
puts("Yes");
|
||||
printf("%d\n", cnt); //输出使先手为胜的方案的数目
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
printf("%d %d\n", ans[i][0], ans[i][1]); //输出若先手为胜的走法
|
||||
}
|
||||
} else { puts("No"); }
|
||||
}
|
||||
//树上删边游戏
|
||||
//给定一棵n个点的有根树, 每次可以删掉一个子树
|
||||
//则叶子节点的SG值为0, 非叶子节点的SG值为其所有孩子节点(SG值 + 1)的异或和
|
||||
|
||||
================动态规划==================
|
||||
//最大子段和 O(n)
|
||||
ll maxSum(int a[], int n, int &st, int &ed) {
|
||||
ll mx = a[0], mxc = 0; st = ed = 0;
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (mxc > 0) { mxc += a[i]; }
|
||||
else { mxc = a[i]; s = i; }
|
||||
if (mxc > mx) { mx = mxc; st = s; ed = i; }
|
||||
}
|
||||
return mx;
|
||||
}
|
||||
//循环数组最大子段和 O(n)
|
||||
const ll INF = 0x7f7f7f7f7f7fLL;
|
||||
ll maxSum_adj(int a[], int n) {
|
||||
ll mx = -INF, mxc = 0, mn = INF, mnc = 0, sum = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
mxc = a[i] + (mxc > 0 ? mxc : 0);
|
||||
if (mx < mxc) { mx = mxc; }
|
||||
mnc = a[i] + (mnc > 0 ? 0 : mnc);
|
||||
if (mn > mnc) { mn = mnc; }
|
||||
sum += a[i];
|
||||
}
|
||||
return mx < 0 || mx > sum - mn ? mx : sum - mn;
|
||||
}
|
||||
//最大M子段和 O(nm)
|
||||
ll dp[N], mxsum[N];
|
||||
ll mxMSum(int a[], int n, int m) {
|
||||
ll mx;
|
||||
for (int i = 1; i <= m; i++) {
|
||||
mx = 0x8f8f8f8f8f8f8f8fLL;
|
||||
for (int j = i; j <= n; j++) {
|
||||
dp[j] = max(dp[j - 1], mxsum[j - 1]) + a[j];
|
||||
mxsum[j - 1] = mx; mx = max(mx, dp[j]);
|
||||
}
|
||||
}
|
||||
return mx;
|
||||
}
|
||||
//最大子阵和 O(n^3)
|
||||
ll presum[N][N];
|
||||
ll maxSum(int a[][N], int h, int w, int &x1, int &y1, int &x2, int &y2) {
|
||||
ll ret = a[0][0], sum; x1 = y1 = x2 = y2 = 0;
|
||||
for (int i = 0; i < h; i++) {
|
||||
presum[i][0] = 0;
|
||||
for (int j = 0; j < w; j++) { presum[i][j + 1] = presum[i][j] + a[i][j]; }
|
||||
}
|
||||
for (int j = 0; j < w; j++) {
|
||||
for (int k = j, s; k < w; k++) {
|
||||
sum = s = 0;
|
||||
for (int i = 0; i < h; i++, s = sum > 0 ? s : i) {
|
||||
if ((sum = (sum > 0 ? sum : 0) + presum[i][k + 1] - presum[i][j]) > ret) {
|
||||
ret = sum; x1 = s; y1 = j; x2 = i; y2 = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//最长上升子序列 Longest Increasing Subsequence O(nlogn)
|
||||
int b[N];
|
||||
int LIS(int a[], int n) {
|
||||
int len = 1; b[0] = a[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
b[a[i] > b[len - 1] ? len++ : lower_bound(b, b + len, a[i]) - b] = a[i]; //非降换为>=和upper_bound
|
||||
}
|
||||
return len;
|
||||
}
|
||||
//最长上升子序列数量 O(nlogn)?
|
||||
int b[N], l[N]; ll cnt[N];
|
||||
vector<int> v[N];
|
||||
ll LIS(int a[], int n) {
|
||||
int len = 1; b[0] = a[0]; l[0] = 1; v[1].push_back(0);
|
||||
for (int i = 1; i < n; i++) {
|
||||
int pos = a[i] > b[len - 1] ? len++ : lower_bound(b, b + len, a[i]) - b;
|
||||
b[pos] = a[i]; l[i] = pos + 1;
|
||||
v[l[i]].push_back(i);
|
||||
}
|
||||
ll ret = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (l[i] == 1) { cnt[i] = 1; continue; }
|
||||
for (int j = 0, ll = l[i] - 1; j < (int)v[ll].size() && v[ll][j] <= i; j++) {
|
||||
if (a[v[ll][j]] < a[i]) { cnt[i] += cnt[v[ll][j]]; }
|
||||
}
|
||||
if (l[i] == len) { ret += cnt[i]; }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//长度为k的上升子序列个数 O(knlogn)
|
||||
int n, k;
|
||||
ll bit[M][N];
|
||||
inline int lowbit(int x) { return x & -x; }
|
||||
void add(int id, int i, ll val) { while (i <= n) { bit[id][i] += val; i += lowbit(i); } }
|
||||
ll sum(int id, int i) { ll ret = 0; while (i) { ret += bit[id][i]; i -= lowbit(i); } return ret; }
|
||||
int main() {
|
||||
scanf("%d%d", &n, &k);
|
||||
add(0, 1, 1);
|
||||
for (int i = 1, x; i <= n; i++) {
|
||||
scanf("%d", &x);
|
||||
for (int j = 1; j <= k; j++) { add(j, x, sum(j - 1, x - 1)); } //非降改为x
|
||||
}
|
||||
printf("%I64d\n", sum(k, n)); //n为元素最大值
|
||||
}
|
||||
//最长公共子序列 Longest Common Subsequence O(n^2)
|
||||
int dp[N][N];
|
||||
int LCS(char *a, char *b) {
|
||||
int m = strlen(a), n = strlen(b);
|
||||
for (int i = 1; i <= m; i++) {
|
||||
for (int j = 1; j <= n; j++) {
|
||||
if (a[i - 1] == b[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; }
|
||||
else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); }
|
||||
}
|
||||
}
|
||||
return dp[m][n];
|
||||
}
|
||||
void printLCS(char *a, char *b) {
|
||||
char s[N] = {0};
|
||||
for (int i = strlen(a), j = strlen(b), k = dp[i][j]; i && j;) {
|
||||
if (a[i - 1] == b[j - 1] && dp[i][j] == dp[i - 1][j - 1] + 1) { s[--k] = a[--i]; --j; }
|
||||
else if (dp[i - 1][j] > dp[i][j - 1]) { i--; }
|
||||
else { j--; }
|
||||
}
|
||||
puts(s);
|
||||
}
|
||||
//最长公共子串 Longest Common Substring
|
||||
//DP O(n^2)
|
||||
int dp[2][N];
|
||||
int LCS_dp(char *a, char *b, int &st1, int &st2) {
|
||||
int m = strlen(a), n = strlen(b), ret = 0, cur = 0; st1 = st2 = -1;
|
||||
for (int i = 0; i < m; i++, cur ^= 1) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (a[i] == b[j]) {
|
||||
dp[cur][j] = i == 0 || j == 0 ? 1 : dp[cur ^ 1][j - 1] + 1;
|
||||
if (dp[cur][j] > ret) { ret = dp[cur][j]; st1 = i + 1 - ret; st2 = j + 1 - ret; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//outputLCS(a, ret, st1);
|
||||
return ret;
|
||||
}
|
||||
//后缀数组 O(nlogn)
|
||||
char *suf[N];
|
||||
int pstrcmp(const void *p, const void *q) {
|
||||
return strcmp(*(char **)p, *(char **)q);
|
||||
}
|
||||
int comlen_suf(const char *p, const char *q) {
|
||||
for (int len = 0; *p && *q && *p++ == *q++;) {
|
||||
len++;
|
||||
if (*p == '#' || *q == '#') { return len; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int LCS_suffix(char *a, char *b) {
|
||||
int m = strlen(a), n = strlen(b), ret = 0, suf_index = 0, len_suf = m + n + 1;
|
||||
char *arr = new char[len_suf + 1];
|
||||
strcpy(arr, a); arr[m] = '#'; strcpy(arr + m + 1, b);
|
||||
for (int i = 0; i < len_suf; i++) { suf[i] = &arr[i]; }
|
||||
qsort(suf, len_suf, sizeof(char *), pstrcmp);
|
||||
for (int i = 0; i < len_suf - 1; i++) {
|
||||
int len = comlen_suf(suf[i], suf[i + 1]);
|
||||
if (len > ret) { ret = len; suf_index = i; }
|
||||
}
|
||||
//outputLCS(suf[suf_index], ret);
|
||||
delete[] arr; return ret;
|
||||
}
|
||||
void outputLCS(char *s, int len, int i = 0) {
|
||||
for (; len--; i++) { putchar(s[i]); } puts("");
|
||||
}
|
||||
//DP 下界O(nlogn) 上界O(nmlog(nm))
|
||||
int c[N * N], d[N * N];
|
||||
int LCS_dp(char *a, char *b) {
|
||||
vector<int> pos[26]; int k = 0, len = 1; d[0] = c[0];
|
||||
for (int i = strlen(b) - 1; i >= 0; i--) { pos[b[i] - 'a'].push_back(i); }
|
||||
for (int i = 0; a[i]; i++) {
|
||||
for (int j = 0; j < (int)pos[a[i] - 'a'].size(); j++) { c[k++] = pos[a[i] - 'a'][j]; }
|
||||
}
|
||||
for (int i = 1; i < k; i++) {
|
||||
d[c[i] > d[len - 1] ? len++ : lower_bound(d, d + len, c[i]) - d] = c[i];
|
||||
}
|
||||
return len;
|
||||
}
|
||||
//最长公共递增子序列 GCIS O(n^2)
|
||||
int dp[N], f[N][N];
|
||||
int GCIS(int a[], int la, int b[], int lb, int ans[]) {
|
||||
//a[1...la], b[1...lb]
|
||||
int mx = 0;
|
||||
memset(f, 0, sizeof(f));
|
||||
memset(dp, 0, sizeof(dp));
|
||||
for (int i = 1; i <= la; i++) {
|
||||
memcpy(f[i], f[i - 1], sizeof(f[0]));
|
||||
for (int j = 1, k = 0; j <= lb; j++) {
|
||||
if (a[j - 1] > b[i - 1] && dp[k] < dp[j]) { k = j; }
|
||||
if (b[j - 1] == a[i - 1] && dp[k] + 1 > dp[j]) { dp[j] = dp[k] + 1; f[i][j] = i * (lb + 1) + k; }
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= lb; i++) { if (dp[i] > dp[mx]) { mx = i; } }
|
||||
for (int i = la * lb + la + mx, j = dp[mx]; j; i = f[i / (lb + 1)][i % (lb + 1)], j--) {
|
||||
ans[j - 1] = b[i % (lb + 1) - 1];
|
||||
}
|
||||
return dp[mx];
|
||||
}
|
||||
//字符串编辑距离 (Levenshtein距离)
|
||||
//操作包括将替换一个字符, 插入一个字符, 删除一个字符
|
||||
int dp[N][N];
|
||||
int LevDist(char *a, char *b) {
|
||||
int n = strlen(a), m = strlen(b);
|
||||
for (int i = 0; i <= n; i++) { dp[i][0] = i; }
|
||||
for (int i = 0; i <= m; i++) { dp[0][i] = i; }
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) {
|
||||
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
|
||||
if (a[i - 1] == b[j - 1]) { dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]); }
|
||||
else { dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1); }
|
||||
}
|
||||
}
|
||||
return dp[n][m];
|
||||
}
|
||||
//字符串距离
|
||||
//非空格字符的距离定义为它们的ASCII码的差的绝对值, 空格字符与其它任意字符之间的距离为已知的定值k
|
||||
int dp[N][N];
|
||||
int dist(char *a, char *b, int k) {
|
||||
int n = strlen(a), m = strlen(b);
|
||||
for (int i = 0; i <= n; i++) { dp[i][0] = i * k; }
|
||||
for (int i = 1; i <= m; i++) { dp[0][i] = i * k; }
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) {
|
||||
dp[i][j] = min(dp[i - 1][j - 1] + abs(a[i - 1] - b[j - 1]), min(dp[i - 1][j], dp[i][j - 1]) + k);
|
||||
}
|
||||
}
|
||||
return dp[n][m];
|
||||
}
|
||||
//TSP问题 O(V^2*2^V)
|
||||
int n, mp[N][N], dp[1 << N][N];
|
||||
int TSP() {
|
||||
memset(dp, 0x1f, sizeof(dp));
|
||||
dp[1][0] = 0;
|
||||
for (int s = 0; s < 1 << n; s++) {
|
||||
for (int v = 0; v < n; v++) {
|
||||
if (dp[s][v] == 0x1f1f1f1f) { continue; }
|
||||
for (int u = 0; u < n; u++) {
|
||||
if (s & 1 << u) { continue; }
|
||||
dp[s | 1 << u][u] = min(dp[s | 1 << u][u], dp[s][v] + mp[v][u]);
|
||||
}
|
||||
}
|
||||
}
|
||||
int ans = 0x1f1f1f1f;
|
||||
for (int i = 0; i < n; i++) { ans = min(ans, dp[(1 << n) - 1][i] + mp[i][0]); }
|
||||
return ans;
|
||||
}
|
||||
//mTSP问题 O(V^2*2^V)
|
||||
int n, mp[N][N], dp[1 << N][N], best[1 << N];
|
||||
bool ok[1 << N]; //该集合状态是否可行
|
||||
int mTSP() {
|
||||
memset(dp, 0x1f, sizeof(dp));
|
||||
memset(best, 0x1f, sizeof(best));
|
||||
dp[1][0] = 0;
|
||||
for (int s = 0; s < 1 << n; s++) {
|
||||
if (!ok[s]) { continue; }
|
||||
for (int v = 0; v < n; v++) {
|
||||
if (!(s & (1 << v)) || dp[s][v] == 0x1f1f1f1f) { continue; }
|
||||
best[s] = min(best[s], dp[s][v] + mp[v][0]);
|
||||
for (int u = 0; u < n; u++) {
|
||||
if (s & (1 << u)) { continue; }
|
||||
dp[s | 1 << u][u] = min(dp[s | 1 << u][u], dp[s][v] + mp[v][u]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int s = 0; s < 1 << n; s++) {
|
||||
if (!(s & 1)) { continue; }
|
||||
for (int i = s & (s - 1); i; i = s & (i - 1)) {
|
||||
best[s] = min(best[s], best[i] + best[(s ^ i) | 1]);
|
||||
}
|
||||
}
|
||||
return best[(1 << n) - 1];
|
||||
}
|
||||
|
||||
==========================黑科技========================
|
||||
//加栈
|
||||
//G++
|
||||
int main() {
|
||||
int sz = 100 << 20; //100MB
|
||||
char *p = (char *)malloc(sz) + sz;
|
||||
__asm__ __volatile__(
|
||||
#if __x86_64__ || __ppc64__ || _WIN64 //64-bit
|
||||
"movq %0, %%rsp\n pushq $_exit\n"
|
||||
#else //32-bit
|
||||
"movl %0, %%esp\n pushl $_exit\n"
|
||||
#endif
|
||||
:: "r"(p));
|
||||
//......
|
||||
exit(0);
|
||||
}
|
||||
//VC++ 100MB
|
||||
#pragma comment(linker, "/STACK:102400000,102400000")
|
||||
|
||||
//位运算
|
||||
//把右边连续的1变成0 | (100101111->100100000) | x and (x+1)
|
||||
//把右起第一个0变成1 | (100101111->100111111) | x or (x+1)
|
||||
//把右边连续的0变成1 | (11011000->11011111) | x or (x-1)
|
||||
//取右边连续的1 | (100101111->1111) | (x xor (x+1)) shr 1
|
||||
//去掉右起第一个1的左边 | (100101000->1000) | x and (x xor (x-1))
|
||||
//枚举i的非空子集j
|
||||
for (int j = i; j; j = (j - 1) & i);
|
||||
|
||||
//builtin函数
|
||||
int __builtin_ffs(int x);
|
||||
int __builtin_ffsll(long long);
|
||||
//Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
|
||||
int __builtin_clz(unsigned int x);
|
||||
int __builtin_clzll(unsigned long long);
|
||||
//Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
|
||||
int __builtin_ctz(unsigned int x);
|
||||
int __builtin_ctzll(unsigned long long);
|
||||
//Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
|
||||
int __builtin_clrsb(int x);
|
||||
int __builtin_clrsbll(long long);
|
||||
//Returns the number of leading redundant sign bits in x, i.e. the number of bits following the most significant bit that are identical to it. There are no special cases for 0 or other values.
|
||||
int __builtin_popcount(unsigned int x);
|
||||
int __builtin_popcountll(unsigned long long);
|
||||
//Returns the number of 1-bits in x.
|
||||
int __builtin_parity(unsigned int x);
|
||||
int __builtin_parityll(unsigned long long);
|
||||
//Returns the parity of x, i.e. the number of 1-bits in x modulo 2.
|
||||
uint32_t __builtin_bswap32(uint32_t x);
|
||||
uint64_t __builtin_bswap64(uint64_t x);
|
||||
//Returns x with the order of the bytes reversed; for example, 0xaabb becomes 0xbbaa. Byte here always means exactly 8 bits.
|
||||
|
||||
//rope O(log(len))
|
||||
#include <ext/rope>
|
||||
using namespace __gnu_cxx;
|
||||
|
||||
//pb_ds库
|
||||
//http://gaotianyu1350.gitcafe.io/2015/02/17/pbds/
|
||||
//priority_queue
|
||||
//定义
|
||||
//包含:ext/pb_ds/priority_queue.hpp
|
||||
//声明:__gnu_pbds::priority_queue<T>
|
||||
//模板参数:
|
||||
//template<typename Value_Type,
|
||||
// typename Cmp_Fn = std::less<Value_Type>,
|
||||
// typename Tag = pairing_heap_tag,
|
||||
// typename Allocator = std::allocator<char>>
|
||||
//class priority_queue;
|
||||
//Value_Type:类型
|
||||
//Cmp_Fn:自定义比较器
|
||||
//Tag:堆的类型。可以是binary_heap_tag(二叉堆)binomial_heap_tag(二项堆)rc_binomial_heap_tag pairing_heap_tag(配对堆)thin_heap_tag
|
||||
//Allocator:不用管
|
||||
//使用
|
||||
//相比STL中的priority_queue,可以
|
||||
//用begin()和end()获取迭代器从而遍历
|
||||
//删除单个元素void erase(point_iterator)
|
||||
//增加或减少某一元素的值void modify(point_iterator, const_reference)
|
||||
//合并void join(priority_queue &other),把other合并到*this,并把other清空
|
||||
//性能分析
|
||||
//五种操作:push、pop、modify、erase、join
|
||||
//pairing_heap_tag:push和joinO(1),其余均摊O(logn)
|
||||
//binary_heap_tag:只支持push和pop,均为均摊O(logn)
|
||||
//binomial_heap_tag:push为均摊O(1),其余为O(logn)
|
||||
//rc_binomial_heap_tag:push为O(1),其余为O(logn)
|
||||
//thin_heap_tag:push为O(1),不支持join,其余为O(logn);但是如果只有increase_key,modify均摊O(1)
|
||||
//不支持不是不能用,而是用起来很慢
|
||||
//大致结论:
|
||||
//对于优化Dijkstra算法,pairing_heap_tag严格快于thin_heap_tag,速度与手写数据结构相当
|
||||
//线段树大法好
|
||||
//binary_heap_tag在绝大多数情况下优于std::priority_queue
|
||||
//pairing_heap_tag在绝大多数情况下优于binomial_heap_tag和rc_binomial_heap_tag
|
||||
//只有push,pop和join操作时,binary_heap_tag速度较快
|
||||
//在有modify操作时,可以考虑pairing_heap_tag,thin_heap_tag或手写数据结构
|
||||
|
||||
//Tree
|
||||
//定义
|
||||
//包含:ext/pb_ds/assoc_container.hpp和ext/pb_ds/tree_policy.hpp
|
||||
//声明:__gnu_pbds::tree<Key, T>
|
||||
//模板参数:
|
||||
//template<typename Key,
|
||||
// typename Mapped,
|
||||
// typename Cmp_Fn = std::less<Key>,
|
||||
// typename Tag = rb_tree_tag,
|
||||
// template<typename Const_Node_Iterator,
|
||||
// typename Node_Iterator,
|
||||
// typename Cmp_Fn_,
|
||||
// typename Allocator_ >
|
||||
// class Node_Update = null_tree_node_update,
|
||||
// typename Allocator = std::allocator<char>>
|
||||
//class tree;
|
||||
//Tag:tree的类型,可以是rb_tree_tag,splay_tree_tag,ov_tree_tag
|
||||
//Node_Update:可以为空,也可以用pb_ds自带的tree_order_statistics_node_update,这样这个tree就会获得两个函数find_by_order和order_of_key
|
||||
//iterator find_by_order(size_type order):找第order + 1小的元素的迭代器,如果order太大会返回end()
|
||||
//size_type order_of_key(const_key_reference r_key):询问这个tree中有多少比r_key小的元素
|
||||
//使用
|
||||
//与map使用方法基本相同,包括begin(),end(),size(),empty(),clear(),find(const Key),
|
||||
//lower_bound(const Key),upper_bound(const Key),erase(iterator),erase(const Key),
|
||||
//insert(const pair<Key, T>),operator[](const Key)
|
||||
//如果想改成set,只需要将第二个参数Mapped改为null_type(在4.4.0及以下版本的编译器中应用null_mapped_type)就可以了。此时迭代器指向的类型会从pair变成Key,和set几乎没有区别
|
||||
//当然还有一些其他用法,如:
|
||||
//void join(tree &other):把other中所有元素移动到*this上(值域不能相交,否则会抛出异常)
|
||||
//void split(const_key_reference r_key, tree &other):清空other,然后把*this中所有大于r_key的元素移动到other
|
||||
//自定义Node_Update使用方法
|
||||
//自带的tree_order_statistics_node_update统计的是子树size
|
||||
//稍加修改就可以统计容易合并的任意信息
|
||||
//以下代码实现了区间求和
|
||||
template<class Node_CItr, class Node_Itr, class Cmp_Fn, class _Alloc>
|
||||
struct my_node_update {
|
||||
virtual Node_CItr node_begin()const = 0;
|
||||
virtual Node_CItr node_end()const = 0;
|
||||
typedef int metadata_type; //节点上记录的额外信息的类型
|
||||
inline void operator()(Node_Itr it, Node_CItr end_it) {
|
||||
Node_Itr l = it.get_l_child(), r = it.get_r_child();
|
||||
int left = 0, right = 0;
|
||||
if (l != end_it) { left = l.get_metadata(); }
|
||||
if (r != end_it) { right = r.get_metadata(); }
|
||||
const_cast<metadata_type &>(it.get_metadata()) = left + right + (*it)->second;
|
||||
}
|
||||
inline int prefix_sum(int x) {
|
||||
int ans = 0;
|
||||
Node_CItr it = node_begin();
|
||||
while (it != node_end()) {
|
||||
Node_CItr l = it.get_l_child(), r = it.get_r_child();
|
||||
if (Cmp_Fn()(x, (*it)->first)) { it = l; }
|
||||
else {
|
||||
ans += (*it)->second;
|
||||
if (l != node_end()) { ans += l.get_metadata(); }
|
||||
it = r;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
inline int interval_sum(int l, int r) {
|
||||
return prefix_sum(r) - prefix_sum(l - 1);
|
||||
}
|
||||
};
|
||||
int main() {
|
||||
tree<int, int, std::less<int>, rb_tree_tag, my_node_update> T;
|
||||
T[2] = 100; T[3] = 1000; T[4] = 10000;
|
||||
printf("%d\n%d\n", T.interval_sum(3, 4), T.prefix_sum(3));
|
||||
}
|
||||
//注意:
|
||||
//对Node_Itr可以做的事情:用get_l_child和get_r_child获取左右儿子,用两个星号(一个星号只是获取了iterator)获取节点信息,用get_metadata获取节点额外信息
|
||||
//operator()的功能是将节点it的信息更新,传入的end_it表示空节点
|
||||
//性能分析
|
||||
//和手写数据结构差不多,rb_tree_tag要更快
|
||||
|
||||
//Hash
|
||||
//定义
|
||||
//包含:ext/pb_ds/assoc_container.hpp和ext/pb_ds/hash_policy.hpp
|
||||
//声明:
|
||||
//__gnu_pbds::cc_hash_table<Key, Mapped>
|
||||
//__gnu_pbds::gp_hash_table<Key, Mapped>
|
||||
//使用
|
||||
//支持find和operator[]
|
||||
|
||||
//Trie
|
||||
//定义
|
||||
//包含:ext/pb_ds/assoc_container.hpp和ext/pb_ds/trie_policy.hpp
|
||||
//声明:__gnu_pbds::trie<Key, Mapped>
|
||||
//模板参数:
|
||||
//template<typename Key,
|
||||
// typename Mapped,
|
||||
// typename Cmp_Fn = std::less<Key>,
|
||||
// typename Tag = pat_trie_tag,
|
||||
// template<typename Const_Node_Iterator,
|
||||
// typename Node_Iterator,
|
||||
// typename E_Access_Traits_,
|
||||
// typename Allocator_>
|
||||
// class Node_Update = null_trie_node_update,
|
||||
// typename Allocator = std::allocator<char>>
|
||||
//class trie;
|
||||
//Key is the key type.
|
||||
//Mapped is the mapped-policy, and is explained in Tutorial::Associative Containers::Associative Containers Others than Maps.
|
||||
//E_Access_Traits is described in Element-Access Traits.
|
||||
//Tag specifies which underlying data structure to use, and is described shortly.
|
||||
//Node_Update is a policy for updating node invariants. This is described in Node Invariants.
|
||||
//Allocator is an allocator type.
|
||||
//功能:
|
||||
//pair<const_iterator, const_iterator> prefix_range(key_const_reference)
|
||||
//Finds the const iterator range corresponding to all values whose prefixes match r_key
|
||||
//如果你想用这个函数,trie的模板参数得这么写trie<string, [your type here], string_trie_e_access_traits<>, pat_trie_tag, trie_prefix_search_node_update>
|
||||
|
||||
//List(用作multimap/multiset)
|
||||
//定义
|
||||
//包含:ext/pb_ds/assoc_container.hpp和ext/pb_ds/list_update_policy.hpp
|
||||
//声明:__gnu_pbds::list_update<Key, Mapped>
|
||||
//模板参数:
|
||||
//template<typename Key,
|
||||
// typename Mapped,
|
||||
// typename Eq_Fn = std::equal_to<Key>,
|
||||
// typename Update_Policy = move_to_front_lu_policy<>,
|
||||
// typename Allocator = std::allocator<char>>
|
||||
//class list_update;
|
||||
|
||||
//总结
|
||||
//priority_queue,与STL相比支持了modify,erase和join
|
||||
//tree,相当于STL中的set/map,还支持split和join,运用tree_order_statistics_node_update还支持查询rank和k小值;更可以自定义Node_Update来维护更多信息
|
||||
//(目前比赛环境中)STL没有的两种hash_table
|
||||
//无脑用pb_ds代替std::set/map/priority_queue不会使程序变得更慢
|
||||
|
||||
|
||||
===================矩阵================
|
||||
//矩阵类
|
||||
template<typename T> struct mat {
|
||||
vector<T> a; int h, w;
|
||||
mat(): a(), h(), w() {}
|
||||
mat(const mat &v): a(v.a), h(v.h), w(v.w) {}
|
||||
mat(const int &_h, const int &_w): a(_h * _w), h(_h), w(_w) { }
|
||||
void init() { a.clear(); a.resize(h * w); }
|
||||
static mat e(const int &_h, const int &_w) {
|
||||
mat res(_h, _w);
|
||||
for (int i = 0, n = min(_h, _w); i < n; i++) { res[i][i] = 1; }
|
||||
return res;
|
||||
}
|
||||
static mat e(const mat &b) { return e(b.h, b.w); }
|
||||
T *operator[](const int &v) { return &a[v * w]; }
|
||||
const T *operator[](const int &v)const { return &a[v * w]; }
|
||||
mat &operator+=(const mat &b) {
|
||||
for (int i = 0, n = h * w; i < n; i++) { a[i] += b.a[i]; }
|
||||
return *this;
|
||||
}
|
||||
mat &operator-=(const mat &b) { return *this += -b; }
|
||||
mat &operator*=(const mat &b) {
|
||||
mat c(h, b.w);
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int k = 0; k < w; k++) {
|
||||
const T &tmp = (*this)[i][k];
|
||||
if (isZero(tmp)) { continue; }
|
||||
for (int j = 0; j < b.w; j++) { c[i][j] = (c[i][j] + tmp * b[k][j])/*%M*/; }
|
||||
}
|
||||
}
|
||||
swap(a, c.a); h = c.h; w = c.w; return *this;
|
||||
}
|
||||
mat operator-()const {
|
||||
mat ret(*this);
|
||||
for (int i = 0, n = h * w; i < n; i++) { ret.a[i] = -ret.a[i]; }
|
||||
return ret;
|
||||
}
|
||||
mat operator+(const mat &b)const { return mat(*this) += b; }
|
||||
mat operator-(const mat &b)const { return mat(*this) -= b; }
|
||||
mat operator*(const mat &b)const { return mat(*this) *= b; }
|
||||
mat operator^(const ll &v)const {
|
||||
mat ret(e(*this)), t(*this);
|
||||
for (ll b = v; b; b >>= 1) { if (b & 1) { ret *= t; } t *= t; }
|
||||
return ret;
|
||||
}
|
||||
bool operator==(const mat &b)const {
|
||||
if (h != b.h || w != b.w) { return false; }
|
||||
for (int i = 0, n = h * w; i < n; i++) { if (!isZero(a[i] - b.a[i])) { return false; } }
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const mat &b)const { return !(*this == b); }
|
||||
T abs(const T &v)const { return v < 0 ? -v : v; }
|
||||
bool isZero(const T &v)const { return abs(v) < 1e-9; }
|
||||
void input() { for (int i = 0, n = h * w; i < n; i++) { scanf("%I64d", &a[i]); } }
|
||||
void print()const {
|
||||
for (int i = 0, n = h * w; i < n; i++) { printf("%I64d%c", a[i], i % w == w - 1 ? '\n' : ' '); }
|
||||
}
|
||||
mat trans()const {
|
||||
mat ret(w, h);
|
||||
for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { ret[i][j] = a[j][i]; } }
|
||||
return ret;
|
||||
}
|
||||
//求逆矩阵 限double 可逆则返回true 结果在参数v中
|
||||
bool inv(mat &v)const {
|
||||
if (h != w) { return false; }
|
||||
int is[N], js[N]; v = *this;
|
||||
for (int k = 0; k < h; k++) {
|
||||
double t = 0;
|
||||
for (int i = k; i < h; i++) {
|
||||
for (int j = k; j < h; j++) {
|
||||
if (abs(v[i][j]) > t) { t = abs(v[is[k] = i][js[k] = j]); }
|
||||
}
|
||||
}
|
||||
if (isZero(t)) { return false; }
|
||||
if (is[k] != k) { for (int j = 0; j < h; j++) { swap(v[k][j], v[is[k]][j]); } }
|
||||
if (js[k] != k) { for (int i = 0; i < h; i++) { swap(v[i][k], v[i][js[k]]); } }
|
||||
v[k][k] = 1.0 / v[k][k];
|
||||
for (int j = 0; j < h; j++) { if (j != k) { v[k][j] *= v[k][k]; } }
|
||||
for (int i = 0; i < h; i++) {
|
||||
if (i != k) { for (int j = 0; j < h; j++) { if (j != k) { v[i][j] -= v[i][k] * v[k][j]; } } }
|
||||
}
|
||||
for (int i = 0; i < h; i++) { if (i != k) { v[i][k] *= -v[k][k]; } }
|
||||
}
|
||||
for (int k = h - 1; k >= 0; k--) {
|
||||
for (int j = 0; j < h; j++) { if (js[k] != k) { swap(v[k][j], v[js[k]][j]); } }
|
||||
for (int i = 0; i < h; i++) { if (is[k] != k) { swap(v[i][k], v[i][is[k]]); } }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//求行列式模M 需逆元
|
||||
ll detmod()const {
|
||||
if (h != w) { return 0; }
|
||||
ll res = 1; mat c(*this);
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < h; j++) { c[i][j] = (c[i][j] % M + M) % M; }
|
||||
}
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = i; j < h; j++) {
|
||||
if (c[j][i] != 0) {
|
||||
for (int k = i; k < h; k++) { swap(c[i][k], c[j][k]); }
|
||||
if (i != j) { res = (-res + M) % M; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c[i][i] == 0) { res = -1; break; }
|
||||
for (int j = i + 1; j < h; j++) {
|
||||
//int mul = (c[j][i] * Inv[c[i][i]]) % M; //打表逆元
|
||||
ll mul = (c[j][i] * inv(c[i][i], M)) % M;
|
||||
for (int k = i; k < h; k++) { c[j][k] = (c[j][k] - (c[i][k] * mul) % M + M) % M; }
|
||||
}
|
||||
res = (res * c[i][i]) % M;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//求行列式 限double
|
||||
double det()const {
|
||||
if (h != w) { return 0; }
|
||||
int sign = 0; double ret = 1.0; mat c(*this);
|
||||
for (int i = 0, j, k; i < h; i++) {
|
||||
if (isZero(c[i][i])) {
|
||||
for (j = i + 1; j < h && isZero(c[j][i]); j++);
|
||||
if (j == h) { return 0; }
|
||||
for (k = i; k < h; k++) { swap(c[i][k], c[j][k]); }
|
||||
sign++;
|
||||
}
|
||||
ret *= c[i][i];
|
||||
for (k = i + 1; k < h; k++) { c[i][k] /= c[i][i]; }
|
||||
for (j = i + 1; j < h; j++) { for (k = i + 1; k < h; k++) { c[j][k] -= c[j][i] * c[i][k]; } }
|
||||
}
|
||||
return sign & 1 ? -ret : ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
131
.ACM-Templates/TXTs/矩阵.txt
Normal file
131
.ACM-Templates/TXTs/矩阵.txt
Normal file
|
@ -0,0 +1,131 @@
|
|||
//矩阵类
|
||||
template<typename T> struct mat {
|
||||
vector<T> a; int h, w;
|
||||
mat(): a(), h(), w() {}
|
||||
mat(const mat &v): a(v.a), h(v.h), w(v.w) {}
|
||||
mat(const int &_h, const int &_w): a(_h * _w), h(_h), w(_w) { }
|
||||
void init() { a.clear(); a.resize(h * w); }
|
||||
static mat e(const int &_h, const int &_w) {
|
||||
mat res(_h, _w);
|
||||
for (int i = 0, n = min(_h, _w); i < n; i++) { res[i][i] = 1; }
|
||||
return res;
|
||||
}
|
||||
static mat e(const mat &b) { return e(b.h, b.w); }
|
||||
T *operator[](const int &v) { return &a[v * w]; }
|
||||
const T *operator[](const int &v)const { return &a[v * w]; }
|
||||
mat &operator+=(const mat &b) {
|
||||
for (int i = 0, n = h * w; i < n; i++) { a[i] += b.a[i]; }
|
||||
return *this;
|
||||
}
|
||||
mat &operator-=(const mat &b) { return *this += -b; }
|
||||
mat &operator*=(const mat &b) {
|
||||
mat c(h, b.w);
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int k = 0; k < w; k++) {
|
||||
const T &tmp = (*this)[i][k];
|
||||
if (isZero(tmp)) { continue; }
|
||||
for (int j = 0; j < b.w; j++) { c[i][j] = (c[i][j] + tmp * b[k][j])/*%M*/; }
|
||||
}
|
||||
}
|
||||
swap(a, c.a); h = c.h; w = c.w; return *this;
|
||||
}
|
||||
mat operator-()const {
|
||||
mat ret(*this);
|
||||
for (int i = 0, n = h * w; i < n; i++) { ret.a[i] = -ret.a[i]; }
|
||||
return ret;
|
||||
}
|
||||
mat operator+(const mat &b)const { return mat(*this) += b; }
|
||||
mat operator-(const mat &b)const { return mat(*this) -= b; }
|
||||
mat operator*(const mat &b)const { return mat(*this) *= b; }
|
||||
mat operator^(const ll &v)const {
|
||||
mat ret(e(*this)), t(*this);
|
||||
for (ll b = v; b; b >>= 1) { if (b & 1) { ret *= t; } t *= t; }
|
||||
return ret;
|
||||
}
|
||||
bool operator==(const mat &b)const {
|
||||
if (h != b.h || w != b.w) { return false; }
|
||||
for (int i = 0, n = h * w; i < n; i++) { if (!isZero(a[i] - b.a[i])) { return false; } }
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const mat &b)const { return !(*this == b); }
|
||||
T abs(const T &v)const { return v < 0 ? -v : v; }
|
||||
bool isZero(const T &v)const { return abs(v) < 1e-9; }
|
||||
void input() { for (int i = 0, n = h * w; i < n; i++) { scanf("%I64d", &a[i]); } }
|
||||
void print()const {
|
||||
for (int i = 0, n = h * w; i < n; i++) { printf("%I64d%c", a[i], i % w == w - 1 ? '\n' : ' '); }
|
||||
}
|
||||
mat trans()const {
|
||||
mat ret(w, h);
|
||||
for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { ret[i][j] = a[j][i]; } }
|
||||
return ret;
|
||||
}
|
||||
//求逆矩阵 限double 可逆则返回true 结果在参数v中
|
||||
bool inv(mat &v)const {
|
||||
if (h != w) { return false; }
|
||||
int is[N], js[N]; v = *this;
|
||||
for (int k = 0; k < h; k++) {
|
||||
double t = 0;
|
||||
for (int i = k; i < h; i++) {
|
||||
for (int j = k; j < h; j++) {
|
||||
if (abs(v[i][j]) > t) { t = abs(v[is[k] = i][js[k] = j]); }
|
||||
}
|
||||
}
|
||||
if (isZero(t)) { return false; }
|
||||
if (is[k] != k) { for (int j = 0; j < h; j++) { swap(v[k][j], v[is[k]][j]); } }
|
||||
if (js[k] != k) { for (int i = 0; i < h; i++) { swap(v[i][k], v[i][js[k]]); } }
|
||||
v[k][k] = 1.0 / v[k][k];
|
||||
for (int j = 0; j < h; j++) { if (j != k) { v[k][j] *= v[k][k]; } }
|
||||
for (int i = 0; i < h; i++) {
|
||||
if (i != k) { for (int j = 0; j < h; j++) { if (j != k) { v[i][j] -= v[i][k] * v[k][j]; } } }
|
||||
}
|
||||
for (int i = 0; i < h; i++) { if (i != k) { v[i][k] *= -v[k][k]; } }
|
||||
}
|
||||
for (int k = h - 1; k >= 0; k--) {
|
||||
for (int j = 0; j < h; j++) { if (js[k] != k) { swap(v[k][j], v[js[k]][j]); } }
|
||||
for (int i = 0; i < h; i++) { if (is[k] != k) { swap(v[i][k], v[i][is[k]]); } }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//求行列式模M 需逆元
|
||||
ll detmod()const {
|
||||
if (h != w) { return 0; }
|
||||
ll res = 1; mat c(*this);
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < h; j++) { c[i][j] = (c[i][j] % M + M) % M; }
|
||||
}
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = i; j < h; j++) {
|
||||
if (c[j][i] != 0) {
|
||||
for (int k = i; k < h; k++) { swap(c[i][k], c[j][k]); }
|
||||
if (i != j) { res = (-res + M) % M; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c[i][i] == 0) { res = -1; break; }
|
||||
for (int j = i + 1; j < h; j++) {
|
||||
//int mul = (c[j][i] * Inv[c[i][i]]) % M; //打表逆元
|
||||
ll mul = (c[j][i] * inv(c[i][i], M)) % M;
|
||||
for (int k = i; k < h; k++) { c[j][k] = (c[j][k] - (c[i][k] * mul) % M + M) % M; }
|
||||
}
|
||||
res = (res * c[i][i]) % M;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//求行列式 限double
|
||||
double det()const {
|
||||
if (h != w) { return 0; }
|
||||
int sign = 0; double ret = 1.0; mat c(*this);
|
||||
for (int i = 0, j, k; i < h; i++) {
|
||||
if (isZero(c[i][i])) {
|
||||
for (j = i + 1; j < h && isZero(c[j][i]); j++);
|
||||
if (j == h) { return 0; }
|
||||
for (k = i; k < h; k++) { swap(c[i][k], c[j][k]); }
|
||||
sign++;
|
||||
}
|
||||
ret *= c[i][i];
|
||||
for (k = i + 1; k < h; k++) { c[i][k] /= c[i][i]; }
|
||||
for (j = i + 1; j < h; j++) { for (k = i + 1; k < h; k++) { c[j][k] -= c[j][i] * c[i][k]; } }
|
||||
}
|
||||
return sign & 1 ? -ret : ret;
|
||||
}
|
||||
};
|
41
.ACM-Templates/TXTs/稀疏表.txt
Normal file
41
.ACM-Templates/TXTs/稀疏表.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
//稀疏表 Sparse Table
|
||||
//一维RMQ 预处理O(nlogn) 查询O(1)
|
||||
//返回最大值 下标从1开始 修改即可返回下标
|
||||
int p[N] = { -1}, dp[N][20];
|
||||
void initRMQ() {
|
||||
for (int i = 1; i <= n; i++) { p[i] = p[i >> 1] + 1; dp[i][0] = a[i]; }
|
||||
for (int j = 1; j <= p[n]; j++) {
|
||||
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
|
||||
dp[i][j] = dp[i][j - 1] > dp[i + (1 << (j - 1))][j - 1] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
inline int query(int l, int r) {
|
||||
if (l > r) { swap(l, r); }
|
||||
int k = p[r - l + 1];
|
||||
return dp[l][k] > dp[r - (1 << k) + 1][k] ? dp[l][k] : dp[r - (1 << k) + 1][k];
|
||||
}
|
||||
//二维RMQ 预处理O(nmlognlogm) 查询O(1) 下标从1开始
|
||||
int p[N] = { -1}, dp[N][N][9][9];
|
||||
void initRMQ() {
|
||||
for (int i = 1; i <= n; i++) {
|
||||
p[i] = p[i >> 1] + 1;
|
||||
for (int j = 1; j <= n; j++) { dp[i][j][0][0] = a[i][j]; }
|
||||
}
|
||||
for (int ii = 0; ii <= p[n]; ii++) {
|
||||
for (int jj = 0; jj <= p[m]; jj++) {
|
||||
if (ii + jj == 0) { continue; }
|
||||
for (int i = 1; i + (1 << ii) - 1 <= n; i++) {
|
||||
for (int j = 1; j + (1 << jj) - 1 <= m; j++) {
|
||||
if (ii) { dp[i][j][ii][jj] = max(dp[i][j][ii - 1][jj], dp[i + (1 << (ii - 1))][j][ii - 1][jj]); }
|
||||
else { dp[i][j][ii][jj] = max(dp[i][j][ii][jj - 1], dp[i][j + (1 << (jj - 1))][ii][jj - 1]); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inline int query(int x1, int y1, int x2, int y2) {
|
||||
if (x1 > x2) { swap(x1, x2); } if (y1 > y2) { swap(y1, y2); }
|
||||
int k1 = p[x2 - x1 + 1], k2 = p[y2 - y1 + 1]; x2 -= (1 << k1) - 1; y2 -= (1 << k2) - 1;
|
||||
return max(max(dp[x1][y1][k1][k2], dp[x1][y2][k1][k2]), max(dp[x2][y1][k1][k2], dp[x2][y2][k1][k2]));
|
||||
}
|
183
.ACM-Templates/TXTs/组合数学.txt
Normal file
183
.ACM-Templates/TXTs/组合数学.txt
Normal file
|
@ -0,0 +1,183 @@
|
|||
//组合数预处理 / 杨辉三角 O(n^2)
|
||||
//C[i][i] = C[i][0] = 1
|
||||
//C[i][j] = C[i - 1][j] + C[i - 1][j - 1], 0 < j < i
|
||||
const int maxc = 105;
|
||||
ll C[maxc][maxc];
|
||||
void calC() {
|
||||
for (int i = 0; i < maxc; i++) { C[i][i] = C[i][0] = 1; }
|
||||
for (int i = 2; i < maxc; i++) {
|
||||
for (int j = 1; j < i; j++) { C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % M; }
|
||||
}
|
||||
}
|
||||
//求组合数不取模 O(n)
|
||||
ll Com(ll n, ll m) {
|
||||
if (m > n) { return 0; }
|
||||
if (m > n - m) { m = n - m; }
|
||||
ll ret = 1;
|
||||
for (ll i = 0, j = 1; i < m; i++) {
|
||||
for (ret *= n - i; j <= m && ret % j == 0; j++) { ret /= j; }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//求组合数取模
|
||||
//p <= 1e6 预处理阶乘逆元 O(min(n, p)) + O(1)
|
||||
ll fac[M] = {1, 1}, invfac[M] = {1, 1};
|
||||
void initFac(ll p) {
|
||||
for (int i = 2; i < p; i++) {
|
||||
fac[i] = fac[i - 1] * i % p; invfac[i] = (-invfac[p % i] * (p / i) % p + p) % p;
|
||||
}
|
||||
for (int i = 2; i < p; i++) { invfac[i] = invfac[i] * invfac[i - 1] % p; }
|
||||
}
|
||||
ll Com(ll n, ll m, ll p) {
|
||||
return n < m ? 0 : fac[n] * invfac[n - m] % p * invfac[m] % p;
|
||||
}
|
||||
//p <= 1e9 在线求逆元 O(nlogp)
|
||||
ll Com(ll n, ll m, ll p) {
|
||||
if (m > n) { return 0; }
|
||||
if (m > n - m) { m = n - m; }
|
||||
ll ret = 1;
|
||||
for (ll i = 1; i <= m; i++) {
|
||||
ll a = (n + i - m) % p, b = i % p;
|
||||
ret = ret * a % p * powMod(b, p - 2, p) % p;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
//Lucas定理
|
||||
ll Lucas(ll n, ll m, ll p) {
|
||||
if (n < m) { return 0; }
|
||||
if (m == 0 && n == 0) { return 1; }
|
||||
return Com(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
|
||||
}
|
||||
//第一类Stirling数 s(p, k)
|
||||
//将p个物体排成k个非空循环排列的方法数
|
||||
//s(p, k)的递推公式:s(p, k) = (p - 1) * s(p - 1, k) + s(p - 1, k - 1), 1 <= k <= p - 1
|
||||
//边界条件:s(p, 0) = 0, p >= 1, s(p, p) = 1, p >= 0
|
||||
const int maxs = 105;
|
||||
ll S[maxs][maxs];
|
||||
void calStir1() {
|
||||
S[0][0] = S[1][1] = 1;
|
||||
for (int i = 2; i < maxs; i++) {
|
||||
for (int j = 1; j <= i; j++) { S[i][j] = ((i - 1) * S[i - 1][j] + S[i - 1][j - 1]) % M; }
|
||||
}
|
||||
}
|
||||
//第二类Stirling数 S(p, k)
|
||||
//将p个物体划分成k个非空的不可辨别的(可以理解为盒子没有编号)集合的方法数
|
||||
//k! * S(p, k)是把p个人分进k间有差别(如被标有房号)的房间(无空房)的方法数
|
||||
//S(p, k)的递推公式是:S(p, k) = k * S(p - 1, k) + S(p - 1, k - 1), 1 <= k <= p - 1
|
||||
//边界条件:S(p, 0) = 0, p >= 1, S(p, p) = 1, p >= 0
|
||||
const int maxs = 105;
|
||||
ll S[maxs][maxs];
|
||||
void calStir2() {
|
||||
S[0][0] = S[1][1] = 1;
|
||||
for (int i = 2; i < maxs; i++) {
|
||||
for (int j = 1; j <= i; j++) { S[i][j] = (j * S[i - 1][j] + S[i - 1][j - 1]) % M; }
|
||||
}
|
||||
}
|
||||
//Bell数
|
||||
//B(n)表示基数为n的集合的划分方法的数目
|
||||
//B(0) = 1, B(n + 1) = sum(C(n, k) * B(k)), 0 <= k <= n
|
||||
//每个贝尔数都是第二类Stirling数的和, 即B(n) = sum(S(n, k)), 1 <= k <= n
|
||||
//Bell三角形
|
||||
//a[0][0] = 1
|
||||
//对于n >= 1, a[n][0] = a[n - 1][n - 1]
|
||||
//对于m, n >= 1, a[n][m] = a[n][m - 1] + a[n - 1][m - 1]
|
||||
//每行首项是贝尔数,每行之和是第二类Stirling数
|
||||
//两个重要的同余性质:
|
||||
//B(p + n) = B(n) + B(n + 1) (mod p)
|
||||
//B(p^m + n) = m * B(n) + B(n + 1) (mod p)
|
||||
//p是不大于100的素数, 这样, 我们可以通过上面的性质来计算Bell数模小于100的素数值
|
||||
//Bell数模素数p的周期为: N(p) = ((p^p) - 1) / (p - 1)
|
||||
const int maxb = 105;
|
||||
ll T[maxb], B[maxb];
|
||||
void calBell() {
|
||||
B[0] = B[1] = T[0] = 1;
|
||||
for (int i = 2; i < maxb; i++) {
|
||||
T[i - 1] = B[i - 1];
|
||||
for (int j = i - 2; j >= 0; j--) { T[j] = (T[j] + T[j + 1]) % M; }
|
||||
B[i] = T[0];
|
||||
}
|
||||
}
|
||||
//计算Bell(n)对999999598 = 2 × 13 × 5281 × 7283取模 O(P^2logP)
|
||||
const int N = 7284, P = 999999598;
|
||||
ll n; int p[5] = {2, 13, 5281, 7283}, B[2][N], T[N];
|
||||
void init() {
|
||||
T[0] = T[1] = B[0][0] = 1; B[0][1] = 2;
|
||||
for (int i = 2, crt = 1; i < N; i++, crt ^= 1) {
|
||||
T[i] = B[crt][0] = B[crt ^ 1][i - 1];
|
||||
for (int j = 1; j <= i; j++) { B[crt][j] = (B[crt ^ 1][j - 1] + B[crt][j - 1]) % P; }
|
||||
}
|
||||
}
|
||||
int b[N], c[N], d[70];
|
||||
int cal(ll n, int mod) {
|
||||
int len = 0;
|
||||
for (int i = 0; i <= mod; i++) { b[i] = T[i] % mod; }
|
||||
while (n) { d[len++] = n % mod; n /= mod; }
|
||||
for (int i = 1; i < len; i++) {
|
||||
for (int j = 1; j <= d[i]; j++) {
|
||||
for (int k = 0; k < mod; k++) { c[k] = (b[k] * i + b[k + 1]) % mod; }
|
||||
c[mod] = (c[0] + c[1]) % mod;
|
||||
for (int k = 0; k <= mod; k++) { b[k] = c[k]; }
|
||||
}
|
||||
}
|
||||
return c[d[0]];
|
||||
}
|
||||
ll bell(ll n) {
|
||||
if (n < N) { return T[n]; }
|
||||
ll t = 0;
|
||||
for (int i = 0; p[i]; i++) {
|
||||
t = (t + (P / p[i]) * powMod(P / p[i], p[i] - 2, p[i]) % P * cal(n, p[i]) % P) % P;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
//卡特兰数 Catalan Number
|
||||
//Cat(1) = 1, Cat(n) = (4n - 2) * Cat(n - 1) / (n + 1) = C(2n, n) / (n + 1) = C(2n, n) - C(2n, n - 1)
|
||||
//从(0, 0)点走到(n, m)点且
|
||||
//不经过对角线的方法数(x > y): C(n + m - 1, m) - C(n + m - 1, m - 1)
|
||||
//不穿过对角线的方法数(x >= y): C(n + m, m) - C(n + m, m - 1)
|
||||
//预处理卡特兰数
|
||||
int a[105][105], b[105]; //大数, 长度
|
||||
void Catalan() {
|
||||
int i, j, len, carry, temp;
|
||||
a[1][0] = b[1] = len = 1;
|
||||
for (i = 2; i <= 100; i++) {
|
||||
for (j = 0; j < len; j++) { //乘法
|
||||
a[i][j] = a[i - 1][j] * (4 * (i - 1) + 2);
|
||||
}
|
||||
carry = 0;
|
||||
for (j = 0; j < len; j++) { //处理相乘结果
|
||||
temp = a[i][j] + carry;
|
||||
a[i][j] = temp % 10;
|
||||
carry = temp / 10;
|
||||
}
|
||||
while (carry) { //进位处理
|
||||
a[i][len++] = carry % 10;
|
||||
carry /= 10;
|
||||
}
|
||||
carry = 0;
|
||||
for (j = len - 1; j >= 0; j--) { //除法
|
||||
temp = carry * 10 + a[i][j];
|
||||
a[i][j] = temp / (i + 1);
|
||||
carry = temp % (i + 1);
|
||||
}
|
||||
while (!a[i][len - 1]) { len--; } //高位零处理
|
||||
b[i] = len;
|
||||
}
|
||||
}
|
||||
//输出大数
|
||||
void printCatalan(int n) {
|
||||
for (int i = b[n] - 1; i >= 0; i--) { printf("%d", a[n][i]); }
|
||||
}
|
||||
//各种情况下小球放盒子的方案数
|
||||
//k个球 m个盒子 是否允许有空盒子 方案数
|
||||
//不同 不同 是 m^k
|
||||
//不同 不同 否 m!*Stirling2(k, m)
|
||||
//不同 相同 是 ∑(m, i=1)Stirling2(k, i)
|
||||
//不同 相同 否 Stirling2(k, m)
|
||||
//相同 不同 是 C(m + k - 1, k)
|
||||
//相同 不同 否 C(k - 1, m - 1)
|
||||
//相同 相同 是 1/(1-x)(1-x^2)...(1-x^m)的x^k项的系数
|
||||
//相同 相同 否 x^m/(1-x)(1-x^2)...(1-x^m)的x^k项的系数
|
||||
//错排公式
|
||||
//D(1) = 0, D(2) = 1, D(n) = (n - 1)(D(n - 2) + D(n - 1))
|
||||
//扩展 Cayley 公式
|
||||
//对于n个点, m个连通块的图, 假设每个连通块有a[i]个点, 那么用s - 1条边把它连通的方案数为n^(s-2)a[1]a[2]...a[m]
|
28
.ACM-Templates/TXTs/莫队.txt
Normal file
28
.ACM-Templates/TXTs/莫队.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
//莫队算法 O(n^1.5)
|
||||
//莫队算法是离线处理一类区间不修改查询类问题的算法
|
||||
//如果你知道了[L,R]的答案, 你可以在O(1)的时间下得到[L,R-1]和[L,R+1]和[L-1,R]和[L+1,R]的答案的话, 就可以使用莫队算法
|
||||
//lydsy 2038: [2009国家集训队]小Z的袜子(hose)
|
||||
int n, m;
|
||||
int c[N], pos[N];
|
||||
int ansup[N], ansdn[N], cnt[N];
|
||||
struct Node {
|
||||
int l, r, id;
|
||||
bool operator<(const Node &b)const { return pos[l] < pos[b.l] || (pos[l] == pos[b.l] && r < b.r); }
|
||||
} q[N];
|
||||
int main() {
|
||||
while (~scanf("%d%d", &n, &m)) {
|
||||
memset(cnt, 0, sizeof(cnt)); ll ans = 0;
|
||||
for (int i = 1, nn = ceil(sqrt(n)); i <= n; i++) { scanf("%d", &c[i]); pos[i] = (i - 1) / nn; }
|
||||
for (int i = 0; i < m; i++) { scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i; }
|
||||
sort(q, q + m);
|
||||
for (int i = 0, l = 1, r = 0; i < m; i++) {
|
||||
for (; l > q[i].l;) { ans += cnt[c[--l]]++; }
|
||||
for (; l < q[i].l;) { ans -= --cnt[c[l++]]; }
|
||||
for (; r < q[i].r;) { ans += cnt[c[++r]]++; }
|
||||
for (; r > q[i].r;) { ans -= --cnt[c[r--]]; }
|
||||
ll dn = (r - l + 1LL) * (r - l) >> 1, gcd = __gcd(ans, dn);
|
||||
ansup[q[i].id] = ans / gcd; ansdn[q[i].id] = dn / gcd;
|
||||
}
|
||||
for (int i = 0; i < m; i++) { printf("%d/%d\n", ansup[i], ansdn[i]); }
|
||||
}
|
||||
}
|
1393
.ACM-Templates/TXTs/计算几何.txt
Normal file
1393
.ACM-Templates/TXTs/计算几何.txt
Normal file
File diff suppressed because it is too large
Load Diff
71
.ACM-Templates/TXTs/输入输出.txt
Normal file
71
.ACM-Templates/TXTs/输入输出.txt
Normal file
|
@ -0,0 +1,71 @@
|
|||
//关闭同步
|
||||
ios_base::sync_with_stdio(false); cin.tie(NULL);
|
||||
//输入一个非负整数
|
||||
template<typename T> void read(T &x) {
|
||||
char c;
|
||||
while (!isdigit(c = getchar()));
|
||||
for (x = 0; isdigit(c); c = getchar()) { x = x * 10 + c - '0'; }
|
||||
}
|
||||
//输入一个整数
|
||||
template<typename T> void read(T &x) {
|
||||
char c; bool neg = false;
|
||||
while ((c = getchar()) != '-' && !isdigit(c));
|
||||
if (c == '-') { neg = true; c = getchar(); }
|
||||
for (x = 0; isdigit(c); c = getchar()) { x = x * 10 + c - '0'; }
|
||||
if (neg) { x = -x; }
|
||||
}
|
||||
//输入一个数(int, long long, float, double)
|
||||
template<typename T> void read(T &x) {
|
||||
char c; bool neg = false;
|
||||
while ((c = getchar()) != '-' && c != '.' && !isdigit(c));
|
||||
if (c == '-') { neg = true; c = getchar(); }
|
||||
for (x = 0; isdigit(c); c = getchar()) { x = x * 10 + c - '0'; }
|
||||
if (c == ' ' || c == '\n' || c == EOF) { if (neg) { x = -x; } return; }
|
||||
for (T bit = 0.1; isdigit(c = getchar()); bit *= 0.1) { x += (c - '0') * bit; }
|
||||
if (neg) { x = -x; }
|
||||
}
|
||||
//空格作为分隔 读取一行的整数
|
||||
const int BUFSIZE = 1 << 20;
|
||||
char BUF[BUFSIZE];
|
||||
void readln(int a[]) {
|
||||
int i = 0; gets(BUF);
|
||||
for (char *p = strtok(BUF, " "); p; p = strtok(NULL, " ")) { sscanf(p, "%d", &a[i++]); }
|
||||
}
|
||||
//输出一个正整数
|
||||
template<typename T> void printn(T x) {
|
||||
if (x > 9) { printn(x / 10); }
|
||||
putchar(x % 10 + '0');
|
||||
}
|
||||
//配合fread
|
||||
const int BUFSIZE = 1 << 20;
|
||||
char BUF[BUFSIZE + 1], *S, *T; bool eof;
|
||||
inline char gc() {
|
||||
if (S == T) {
|
||||
S = BUF; T = BUF + fread(BUF, 1, BUFSIZE, stdin);
|
||||
if (S == T) { eof = true; return EOF; }
|
||||
}
|
||||
return *S++;
|
||||
}
|
||||
template<typename T> void ni(T &x) {
|
||||
char c; bool neg = false; x = 0;
|
||||
while ((c = gc()) != '-' && !isdigit(c));
|
||||
if (eof) { return; }
|
||||
if (c == '-') { neg = true; c = gc(); }
|
||||
for (; isdigit(c); c = gc()) { x = x * 10 + c - '0'; }
|
||||
if (neg) { x = -x; }
|
||||
}
|
||||
void nd(double &x) {
|
||||
char c; bool neg = false; x = 0;
|
||||
while ((c = gc()) != '-' && !isdigit(c));
|
||||
if (eof) { return; }
|
||||
if (c == '-') { neg = true; c = gc(); }
|
||||
for (; isdigit(c); c = gc()) { x = x * 10 + c - '0'; }
|
||||
if (c == '.') { for (double bit = 0.1; isdigit(c = gc()); bit *= 0.1) { x += (c - '0') * bit; } }
|
||||
if (neg) { x = -x; }
|
||||
}
|
||||
void ns(char *s) {
|
||||
char c;
|
||||
while (isspace(c = gc()));
|
||||
if (eof) { return; }
|
||||
for (; !isspace(c); c = gc()) { *s++ = c; } *s = 0;
|
||||
}
|
195
.ACM-Templates/TXTs/高精度.txt
Normal file
195
.ACM-Templates/TXTs/高精度.txt
Normal file
|
@ -0,0 +1,195 @@
|
|||
//高精度整数
|
||||
const int BASE = 1000000000;
|
||||
const int BASEDIGITS = 9;
|
||||
struct bint {
|
||||
vector<int> s; char sign;
|
||||
bint(): s(), sign(1) {}
|
||||
bint(const ll &v): s(), sign(v < 0 ? -1 : 1) {
|
||||
for (ll t = v < 0 ? -v : v; t; t /= BASE) { s.push_back(t % BASE); }
|
||||
}
|
||||
bint(const string &v): s(), sign(1) {
|
||||
int beg = 0;
|
||||
for (; beg < (int)v.size() && (v[beg] == '-' || v[beg] == '+'); beg++) {
|
||||
if (v[beg] == '-') { sign = -1; }
|
||||
}
|
||||
for (int i = (int)v.size() - 1, x, j; i >= beg; i -= BASEDIGITS) {
|
||||
for (x = 0, j = max(beg, i - BASEDIGITS + 1); j <= i; x = x * 10 + v[j++] - '0');
|
||||
s.push_back(x);
|
||||
}
|
||||
trim();
|
||||
}
|
||||
bint &operator=(const bint &v) { sign = v.sign; s = v.s; return *this; }
|
||||
bint &operator+=(const bint &v) {
|
||||
if (sign == v.sign) {
|
||||
for (int i = 0, is = 0, len = max(s.size(), v.s.size()); i < len || is; i++) {
|
||||
if (i == (int)s.size()) { s.push_back(0); }
|
||||
s[i] += is + (i < (int)v.s.size() ? v.s[i] : 0);
|
||||
if ((is = s[i] >= BASE)) { s[i] -= BASE; }
|
||||
}
|
||||
return *this;
|
||||
} else { return *this -= -v; }
|
||||
}
|
||||
bint &operator-=(const bint &v) {
|
||||
if (sign == v.sign) {
|
||||
if (cmp(v, 0) != -1) {
|
||||
for (int i = 0, is = 0; i < (int)v.s.size() || is; i++) {
|
||||
s[i] -= is + (i < (int)v.s.size() ? v.s[i] : 0);
|
||||
if ((is = s[i] < 0)) { s[i] += BASE; }
|
||||
}
|
||||
trim(); return *this;
|
||||
} else { return *this = -(bint(v) -= *this); }
|
||||
} else { return *this += -v; }
|
||||
}
|
||||
bint &operator*=(const bint &v) {
|
||||
vector<ll> num(s.size() + v.s.size());
|
||||
for (int i = 0; i < (int)s.size(); i++) {
|
||||
for (int j = 0; j < (int)v.s.size(); j++) {
|
||||
num[i + j] += (ll)s[i] * v.s[j];
|
||||
if (num[i + j] >= BASE) { num[i + j + 1] += num[i + j] / BASE; num[i + j] %= BASE; }
|
||||
}
|
||||
}
|
||||
sign *= v.sign; s.resize(num.size());
|
||||
for (int i = 0; i < (int)num.size(); i++) { s[i] = num[i]; }
|
||||
trim(); return *this;
|
||||
}
|
||||
bint &operator/=(const bint &v) { return *this = divmod(*this, v).first; }
|
||||
bint &operator%=(const bint &v) { return *this = divmod(*this, v).second; }
|
||||
bint operator-()const { bint ret(*this); ret.sign = -sign; return ret; }
|
||||
bint operator+(const bint &v)const { return bint(*this) += v; }
|
||||
bint operator-(const bint &v)const { return bint(*this) -= v; }
|
||||
bint operator*(const bint &v)const { return bint(*this) *= v; }
|
||||
bint operator/(const bint &v)const { return divmod(*this, v).first; }
|
||||
bint operator%(const bint &v)const { return divmod(*this, v).second; }
|
||||
bint operator^(const ll &v)const {
|
||||
bint ret(1), t(*this);
|
||||
for (ll b = v; b; b >>= 1) { if (b & 1) { ret *= t; } t *= t; }
|
||||
return ret;
|
||||
}
|
||||
//乘除法辅助函数
|
||||
friend pair<bint, bint> divmod(const bint &a, const bint &b) {
|
||||
int norm = BASE / (b.s.back() + 1);
|
||||
bint x = a.abs().mul(norm), y = b.abs().mul(norm), q, r; q.s.resize(x.s.size());
|
||||
for (int i = (int)x.s.size() - 1; i >= 0; i--) {
|
||||
r = r.mul(BASE); r += x.s[i];
|
||||
int s1 = r.s.size() <= y.s.size() ? 0 : r.s[y.s.size()];
|
||||
int s2 = r.s.size() + 1 <= y.s.size() ? 0 : r.s[y.s.size() - 1];
|
||||
int d = ((ll)BASE * s1 + s2) / y.s.back();
|
||||
r -= y.mul(d);
|
||||
while (r.cmp(0, 1) == -1) { r += y; --d; }
|
||||
q.s[i] = d;
|
||||
}
|
||||
q.sign = a.sign * b.sign; q.trim(); r.sign = a.sign; r.trim();
|
||||
return make_pair(q, r.div(norm));
|
||||
}
|
||||
bint mul(int v)const {
|
||||
bint ret(*this);
|
||||
if (v < 0) { ret.sign = -ret.sign; v = -v; }
|
||||
for (int i = 0, is = 0; i < (int)ret.s.size() || is; i++) {
|
||||
if (i == (int)s.size()) { ret.s.push_back(0); }
|
||||
ll a = ret.s[i] * (ll)v + is; is = a / BASE; ret.s[i] = a % BASE;
|
||||
}
|
||||
ret.trim(); return ret;
|
||||
}
|
||||
bint div(int v)const {
|
||||
bint ret(*this);
|
||||
if (v < 0) { ret.sign = -ret.sign; v = -v; }
|
||||
for (int i = (int)ret.s.size() - 1, rem = 0; i >= 0; i--) {
|
||||
ll a = ret.s[i] + rem * (ll)BASE; ret.s[i] = a / v; rem = a % v;
|
||||
}
|
||||
ret.trim(); return ret;
|
||||
}
|
||||
int mod(int v)const {
|
||||
if (v < 0) { v = -v; }
|
||||
int m = 0;
|
||||
for (int i = (int)s.size() - 1; i >= 0; i--) { m = (s[i] + m * (ll)BASE) % v; }
|
||||
return m * sign;
|
||||
}
|
||||
bool operator<(const bint &v)const { return cmp(v) < 0; }
|
||||
bool operator>(const bint &v)const { return cmp(v) > 0; }
|
||||
bool operator<=(const bint &v)const { return cmp(v) <= 0; }
|
||||
bool operator>=(const bint &v)const { return cmp(v) >= 0; }
|
||||
bool operator==(const bint &v)const { return cmp(v) == 0; }
|
||||
bool operator!=(const bint &v)const { return cmp(v) != 0; }
|
||||
int cmp(const bint &v, bool is = 1)const {
|
||||
if (is) { if (sign > v.sign) { return 1; } if (sign < v.sign) { return -1; } }
|
||||
int d = sign > 0 || !is ? 1 : -1;
|
||||
if (s.size() > v.s.size()) { return d; }
|
||||
if (s.size() < v.s.size()) { return -d; }
|
||||
for (int i = (int)s.size() - 1; i >= 0; i--) {
|
||||
if (s[i] > v.s[i]) { return d; } if (s[i] < v.s[i]) { return -d; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bint abs()const { bint ret(*this); ret.sign *= ret.sign; return ret; }
|
||||
void trim() {
|
||||
while (!s.empty() && !s.back()) { s.pop_back(); }
|
||||
if (s.empty()) { sign = 1; }
|
||||
}
|
||||
void print()const {
|
||||
if (sign == -1) { putchar('-'); }
|
||||
printf("%d", s.empty() ? 0 : s.back());
|
||||
for (int i = (int)s.size() - 2; i >= 0; i--) { printf("%09d", s[i]); }
|
||||
}
|
||||
friend istream &operator>>(istream &in, bint &v) { string s; in >> s; v = s; return in; }
|
||||
friend ostream &operator<<(ostream &out, const bint &v) {
|
||||
if (v.sign == -1) { out << '-'; }
|
||||
out << setfill('0') << (v.s.empty() ? 0 : v.s.back());
|
||||
for (int i = (int)v.s.size() - 2; i >= 0; i--) { out << setw(BASEDIGITS) << v.s[i]; }
|
||||
return out << setfill(' ');
|
||||
}
|
||||
string toString()const {
|
||||
if (s.empty()) { return "0"; }
|
||||
string ret, x;
|
||||
if (sign == -1) { ret += '-'; }
|
||||
for (int o = s[s.size() - 1]; o; o /= 10) { x += o % 10 + '0'; }
|
||||
for (int i = (int)x.size() - 1; i >= 0; i--) { ret += x[i]; }
|
||||
for (int i = (int)s.size() - 2; i >= 0; i--) {
|
||||
x.clear();
|
||||
for (int j = 0, p = s[i]; j < BASEDIGITS; j++, p /= 10) { x += p % 10 + '0'; }
|
||||
for (int j = BASEDIGITS - 1; j >= 0; j--) { ret += x[j]; }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
operator bool()const { return s.size() && !(s.size() == 1 && !s[0]); }
|
||||
//高精度开方
|
||||
bint sqrt()const {
|
||||
bint ret, t(*this); ret.s.resize((t.s.size() + 1) >> 1);
|
||||
for (int i = (int)ret.s.size() - 1; i >= 0; i--) {
|
||||
int l = 0, r = BASE - 1, mid = ret.s[i] = (l + r + 1) >> 1;
|
||||
while (l < r) {
|
||||
if (comp(ret, mid, i - 1, t)) { r = mid - 1; }
|
||||
else { l = mid; }
|
||||
mid = ret.s[i] = (l + r + 1) >> 1;
|
||||
}
|
||||
sub(t, ret, mid, i - 1); ret.s[i] += mid;
|
||||
}
|
||||
for (int i = 0; i < (int)ret.s.size(); i++) { ret.s[i] >>= 1; }
|
||||
ret.trim(); return ret;
|
||||
}
|
||||
void sub(bint &a, const bint &b, const int &k, const int &d)const {
|
||||
for (int i = d + 1, l = b.s.size() + d; i <= l; i++) {
|
||||
ll tmp = a.s[i] - (ll)b.s[i - d - 1] * k;
|
||||
if (tmp < 0) { a.s[i + 1] += (tmp - BASE + 1) / BASE; a.s[i] = tmp - (tmp - BASE + 1) / BASE * BASE; }
|
||||
else { a.s[i] = tmp; }
|
||||
}
|
||||
for (int i = b.s.size() + d + 1; i < (int)a.s.size() && a.s[i] < 0; i++) {
|
||||
a.s[i + 1] += (a.s[i] - BASE + 1) / BASE; a.s[i] -= (a.s[i] - BASE + 1) / BASE * BASE;
|
||||
}
|
||||
a.trim();
|
||||
}
|
||||
bool comp(const bint &a, const int &c, const int &d, const bint &b)const {
|
||||
int l = -(BASE << 1); ll t = 0;
|
||||
if (b.s.size() < a.s.size() + d && c) { return true; }
|
||||
for (int i = (int)b.s.size() - 1; i > d; i--) {
|
||||
t = t * BASE + (ll)(i - d - 1 < (int)a.s.size() ? a.s[i - d - 1] : 0) * c - b.s[i];
|
||||
if (t > 0) { return true; }
|
||||
if (t < l) { return false; }
|
||||
}
|
||||
for (int i = d - 1; i >= 0; i--) {
|
||||
t = t * BASE - b.s[i];
|
||||
if (t > 0) { return true; }
|
||||
if (t < l) { return false; }
|
||||
}
|
||||
return t > 0;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user