struct Mat {
static const LL M = 2;
LL v[M][M];
Mat() { memset(v, 0, sizeof v); }
void eye() { FOR (i, 0, M) v[i][i] = 1; }
LL* operator [] (LL x) { return v[x]; }
const LL* operator [] (LL x) const { return v[x]; }
Mat operator * (const Mat& B) {
const Mat& A = *this;
Mat ret;
FOR (k, 0, M)
FOR (i, 0, M) if (A[i][k])
FOR (j, 0, M)
ret[i][j] = (ret[i][j] + A[i][k] * B[k][j]) % MOD;
return ret;
}
Mat pow(LL n) const {
Mat A = *this, ret; ret.eye();
for (; n; n >>= 1, A = A * A)
if (n & 1) ret = ret * A;
return ret;
}
Mat operator + (const Mat& B) {
const Mat& A = *this;
Mat ret;
FOR (i, 0, M)
FOR (j, 0, M)
ret[i][j] = (A[i][j] + B[i][j]) % MOD;
return ret;
}
void prt() const {
FOR (i, 0, M)
FOR (j, 0, M)
printf("%lld%c", (*this)[i][j], j == M - 1 ? '\n' : ' ');
}
};
- 线性筛
const LL p_max = 1E6 + 100;
LL pr[p_max], p_sz;
void get_prime() {
static bool vis[p_max];
FOR (i, 2, p_max) {
if (!vis[i]) pr[p_sz++] = i;
FOR (j, 0, p_sz) {
if (pr[j] * i >= p_max) break;
vis[pr[j] * i] = 1;
if (i % pr[j] == 0) break;
}
}
}
- 线性筛+欧拉函数
const LL p_max = 1E5 + 100;
LL phi[p_max];
void get_phi() {
phi[1] = 1;
static bool vis[p_max];
static LL prime[p_max], p_sz, d;
FOR (i, 2, p_max) {
if (!vis[i]) {
prime[p_sz++] = i;
phi[i] = i - 1;
}
for (LL j = 0; j < p_sz && (d = i * prime[j]) < p_max; ++j) {
vis[d] = 1;
if (i % prime[j] == 0) {
phi[d] = phi[i] * prime[j];
break;
}
else phi[d] = phi[i] * (prime[j] - 1);
}
}
}
- 线性筛+莫比乌斯函数
const LL p_max = 1E5 + 100;
LL mu[p_max];
void get_mu() {
mu[1] = 1;
static bool vis[p_max];
static LL prime[p_max], p_sz, d;
FOR (i, 2, p_max) {
if (!vis[i]) {
prime[p_sz++] = i;
mu[i] = -1;
}
for (LL j = 0; j < p_sz && (d = i * prime[j]) < p_max; ++j) {
vis[d] = 1;
if (i % prime[j] == 0) {
mu[d] = 0;
break;
}
else mu[d] = -mu[i];
}
}
}
namespace min25 {
const int M = 1E6 + 100;
LL B, N;
// g(x)
inline LL pg(LL x) { return 1; }
inline LL ph(LL x) { return x % MOD; }
// Sum[g(i),{x,2,x}]
inline LL psg(LL x) { return x % MOD - 1; }
inline LL psh(LL x) {
static LL inv2 = (MOD + 1) / 2;
x %= MOD;
return x * (x + 1) % MOD * inv2 % MOD - 1;
}
// f(pp=p^k)
inline LL fpk(LL p, LL e, LL pp) { return (pp - pp / p) % MOD; }
// f(p) = fgh(g(p), h(p))
inline LL fgh(LL g, LL h) { return h - g; }
LL pr[M], pc, sg[M], sh[M];
void get_prime(LL n) {
static bool vis[M]; pc = 0;
FOR (i, 2, n + 1) {
if (!vis[i]) {
pr[pc++] = i;
sg[pc] = (sg[pc - 1] + pg(i)) % MOD;
sh[pc] = (sh[pc - 1] + ph(i)) % MOD;
}
FOR (j, 0, pc) {
if (pr[j] * i > n) break;
vis[pr[j] * i] = 1;
if (i % pr[j] == 0) break;
}
}
}
LL w[M];
LL id1[M], id2[M], h[M], g[M];
inline LL id(LL x) { return x <= B ? id1[x] : id2[N / x]; }
LL go(LL x, LL k) {
if (x <= 1 || (k >= 0 && pr[k] > x)) return 0;
LL t = id(x);
LL ans = fgh((g[t] - sg[k + 1]), (h[t] - sh[k + 1]));
FOR (i, k + 1, pc) {
LL p = pr[i];
if (p * p > x) break;
ans -= fgh(pg(p), ph(p));
for (LL pp = p, e = 1; pp <= x; ++e, pp = pp * p)
ans += fpk(p, e, pp) * (1 + go(x / pp, i)) % MOD;
}
return ans % MOD;
}
LL solve(LL _N) {
N = _N;
B = sqrt(N + 0.5);
get_prime(B);
int sz = 0;
for (LL l = 1, v, r; l <= N; l = r + 1) {
v = N / l; r = N / v;
w[sz] = v; g[sz] = psg(v); h[sz] = psh(v);
if (v <= B) id1[v] = sz; else id2[r] = sz;
sz++;
}
FOR (k, 0, pc) {
LL p = pr[k];
FOR (i, 0, sz) {
LL v = w[i]; if (p * p > v) break;
LL t = id(v / p);
g[i] = (g[i] - (g[t] - sg[k]) * pg(p)) % MOD;
h[i] = (h[i] - (h[t] - sh[k]) * ph(p)) % MOD;
}
}
return (go(N, -1) % MOD + MOD + 1) % MOD;
}
pair<LL, LL> sump(LL l, LL r) {
return {h[id(r)] - h[id(l - 1)],
g[id(r)] - g[id(l - 1)]};
}
}
求
构造一个积性函数
\begin{eqnarray} g(1)S(n)&=&\sum_{i=1}^n (fg)(i)-\sum_{i= 1}^{n}\sum_{d|i,d<i}f(d)g(\frac{n}{d}) \ &\overset{t=\frac{i}{d}}{=}& \sum_{i=1}^n (fg)(i)-\sum_{t=2}^{n} g(t) S(\lfloor \frac{n}{t} \rfloor) \end{eqnarray}
当然,要能够由此计算
-
$f*g$ 要能够快速求前缀和。 -
$g$ 要能够快速求分段和(前缀和)。 - 对于正常的积性函数
$g(1)=1$ ,所以不会有什么问题。
在预处理
namespace dujiao {
const int M = 5E6;
LL f[M] = {0, 1};
void init() {
static bool vis[M];
static LL pr[M], p_sz, d;
FOR (i, 2, M) {
if (!vis[i]) { pr[p_sz++] = i; f[i] = -1; }
FOR (j, 0, p_sz) {
if ((d = pr[j] * i) >= M) break;
vis[d] = 1;
if (i % pr[j] == 0) {
f[d] = 0;
break;
} else f[d] = -f[i];
}
}
FOR (i, 2, M) f[i] += f[i - 1];
}
inline LL s_fg(LL n) { return 1; }
inline LL s_g(LL n) { return n; }
LL N, rd[M];
bool vis[M];
LL go(LL n) {
if (n < M) return f[n];
LL id = N / n;
if (vis[id]) return rd[id];
vis[id] = true;
LL& ret = rd[id] = s_fg(n);
for (LL l = 2, v, r; l <= n; l = r + 1) {
v = n / l; r = n / v;
ret -= (s_g(r) - s_g(l - 1)) * go(v);
}
return ret;
}
LL solve(LL n) {
N = n;
memset(vis, 0, sizeof vis);
return go(n);
}
}
- 前置: 快速乘、快速幂
- int 范围内只需检查 2, 7, 61
- long long 范围 2, 325, 9375, 28178, 450775, 9780504, 1795265022
- 3E15内 2, 2570940, 880937, 610386380, 4130785767
- 4E13内 2, 2570940, 211991001, 3749873356
- http://miller-rabin.appspot.com/
bool checkQ(LL a, LL n) {
if (n == 2) return 1;
if (n == 1 || !(n & 1)) return 0;
LL d = n - 1;
while (!(d & 1)) d >>= 1;
LL t = bin(a, d, n); // 不一定需要快速乘
while (d != n - 1 && t != 1 && t != n - 1) {
t = mul(t, t, n);
d <<= 1;
}
return t == n - 1 || d & 1;
}
bool primeQ(LL n) {
static vector<LL> t = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
if (n <= 1) return false;
for (LL k: t) if (!checkQ(k, n)) return false;
return true;
}
mt19937 mt(time(0));
LL pollard_rho(LL n, LL c) {
LL x = uniform_int_distribution<LL>(1, n - 1)(mt), y = x;
auto f = [&](LL v) { LL t = mul(v, v, n) + c; return t < n ? t : t - n; };
while (1) {
x = f(x); y = f(f(y));
if (x == y) return n;
LL d = gcd(abs(x - y), n);
if (d != 1) return d;
}
}
LL fac[100], fcnt;
void get_fac(LL n, LL cc = 19260817) {
if (n == 4) { fac[fcnt++] = 2; fac[fcnt++] = 2; return; }
if (primeQ(n)) { fac[fcnt++] = n; return; }
LL p = n;
while (p == n) p = pollard_rho(n, --cc);
get_fac(p); get_fac(n / p);
}
void go_fac(LL n) { fcnt = 0; if (n > 1) get_fac(n); }
namespace BerlekampMassey {
using V = vector<LL>;
inline void up(LL& a, LL b) { (a += b) %= MOD; }
V mul(const V&a, const V& b, const V& m, int k) {
V r; r.resize(2 * k - 1);
FOR (i, 0, k) FOR (j, 0, k) up(r[i + j], a[i] * b[j]);
FORD (i, k - 2, -1) {
FOR (j, 0, k) up(r[i + j], r[i + k] * m[j]);
r.pop_back();
}
return r;
}
V pow(LL n, const V& m) {
int k = (int) m.size() - 1; assert (m[k] == -1 || m[k] == MOD - 1);
V r(k), x(k); r[0] = x[1] = 1;
for (; n; n >>= 1, x = mul(x, x, m, k))
if (n & 1) r = mul(x, r, m, k);
return r;
}
LL go(const V& a, const V& x, LL n) {
// a: (-1, a1, a2, ..., ak).reverse
// x: x1, x2, ..., xk
// x[n] = sum[a[i]*x[n-i],{i,1,k}]
int k = (int) a.size() - 1;
if (n <= k) return x[n - 1];
if (a.size() == 2) return x[0] * bin(a[0], n - 1, MOD) % MOD;
V r = pow(n - 1, a);
LL ans = 0;
FOR (i, 0, k) up(ans, r[i] * x[i]);
return (ans + MOD) % MOD;
}
V BM(const V& x) {
V C{-1}, B{-1};
LL L = 0, m = 1, b = 1;
FOR (n, 0, x.size()) {
LL d = 0;
FOR (i, 0, L + 1) up(d, C[i] * x[n - i]);
if (d == 0) { ++m; continue; }
V T = C;
LL c = MOD - d * get_inv(b, MOD) % MOD;
FOR (_, C.size(), B.size() + m) C.push_back(0);
FOR (i, 0, B.size()) up(C[i + m], c * B[i]);
if (2 * L > n) { ++m; continue; }
L = n + 1 - L; B.swap(T); b = d; m = 1;
}
reverse(C.begin(), C.end());
return C;
}
}
- 求
$ax+by=gcd(a,b)$ 的一组解 - 如果
$a$ 和$b$ 互素,那么$x$ 是$a$ 在模$b$ 下的逆元 - 注意
$x$ 和$y$ 可能是负数
LL ex_gcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) { x = 1; y = 0; return a; }
LL ret = ex_gcd(b, a % b, y, x);
y -= a / b * x;
return ret;
}
- 卡常欧几里得
inline int ctz(LL x) { return __builtin_ctzll(x); }
LL gcd(LL a, LL b) {
if (!a) return b; if (!b) return a;
int t = ctz(a | b);
a >>= ctz(a);
do {
b >>= ctz(b);
if (a > b) swap(a, b);
b -= a;
} while (b);
return a << t;
}
-
$m = \lfloor \frac{an+b}{c} \rfloor$ . -
$f(a,b,c,n)=\sum_{i=0}^n\lfloor\frac{ai+b}{c}\rfloor$ : 当$a \ge c$ or$b \ge c$ 时,$f(a,b,c,n)=(\frac{a}{c})n(n+1)/2+(\frac{b}{c})(n+1)+f(a \bmod c,b \bmod c,c,n)$;否则$f(a,b,c,n)=nm-f(c,c-b-1,a,m-1)$ 。 -
$g(a,b,c,n)=\sum_{i=0}^n i \lfloor\frac{ai+b}{c}\rfloor$ : 当$a \ge c$ or$b \ge c$ 时,$g(a,b,c,n)=(\frac{a}{c})n(n+1)(2n+1)/6+(\frac{b}{c})n(n+1)/2+g(a \bmod c,b \bmod c,c,n)$;否则$g(a,b,c,n)=\frac{1}{2} (n(n+1)m-f(c,c-b-1,a,m-1)-h(c,c-b-1,a,m-1))$ 。 -
$h(a,b,c,n)=\sum_{i=0}^n\lfloor \frac{ai+b}{c} \rfloor^2$ : 当$a \ge c$ or$b \ge c$ 时,$h(a,b,c,n)=(\frac{a}{c})^2 n(n+1)(2n+1)/6 +(\frac{b}{c})^2 (n+1)+(\frac{a}{c})(\frac{b}{c})n(n+1)+h(a \bmod c, b \bmod c,c,n)+2(\frac{a}{c})g(a \bmod c,b \bmod c,c,n)+2(\frac{b}{c})f(a \bmod c,b \bmod c,c,n)$;否则$h(a,b,c,n)=nm(m+1)-2g(c,c-b-1,a,m-1)-2f(c,c-b-1,a,m-1)-f(a,b,c,n)$ 。
-
如果
$p$ 不是素数,使用拓展欧几里得 -
前置模板:快速幂 / 扩展欧几里得
inline LL get_inv(LL x, LL p) { return bin(x, p - 2, p); }
LL get_inv(LL a, LL M) {
static LL x, y;
assert(exgcd(a, M, x, y) == 1);
return (x % M + M) % M;
}
- 预处理 1~n 的逆元
LL inv[N];
void inv_init(LL n, LL p) {
inv[1] = 1;
FOR (i, 2, n)
inv[i] = (p - p / i) * inv[p % i] % p;
}
- 预处理阶乘及其逆元
LL invf[M], fac[M] = {1};
void fac_inv_init(LL n, LL p) {
FOR (i, 1, n)
fac[i] = i * fac[i - 1] % p;
invf[n - 1] = bin(fac[n - 1], p - 2, p);
FORD (i, n - 2, -1)
invf[i] = invf[i + 1] * (i + 1) % p;
}
- 如果数较小,模较大时使用逆元
- 前置模板:逆元-预处理阶乘及其逆元
inline LL C(LL n, LL m) { // n >= m >= 0
return n < m || m < 0 ? 0 : fac[n] * invf[m] % MOD * invf[n - m] % MOD;
}
- 如果模数较小,数字较大,使用 Lucas 定理
- 前置模板可选1:求组合数 (如果使用阶乘逆元,需
fac_inv_init(MOD, MOD);
) - 前置模板可选2:模数不固定下使用,无法单独使用。
LL C(LL n, LL m) { // m >= n >= 0
if (m - n < n) n = m - n;
if (n < 0) return 0;
LL ret = 1;
FOR (i, 1, n + 1)
ret = ret * (m - n + i) % MOD * bin(i, MOD - 2, MOD) % MOD;
return ret;
}
LL Lucas(LL n, LL m) { // m >= n >= 0
return m ? C(n % MOD, m % MOD) * Lucas(n / MOD, m / MOD) % MOD : 1;
}
- 组合数预处理
LL C[M][M];
void init_C(int n) {
FOR (i, 0, n) {
C[i][0] = C[i][i] = 1;
FOR (j, 1, i)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
- 绝对值是
$n$ 个元素划分为$k$ 个环排列的方案数。 $s(n,k)=s(n-1,k-1)+(n-1)s(n-1,k)$
-
$n$ 个元素划分为$k$ 个等价类的方案数 $S(n, k)=S(n-1,k-1)+kS(n-1, k)$
S[0][0] = 1;
FOR (i, 1, N)
FOR (j, 1, i + 1) S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j]) % MOD;
LL wn[N << 2], rev[N << 2];
int NTT_init(int n_) {
int step = 0; int n = 1;
for ( ; n < n_; n <<= 1) ++step;
FOR (i, 1, n)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (step - 1));
int g = bin(G, (MOD - 1) / n, MOD);
wn[0] = 1;
for (int i = 1; i <= n; ++i)
wn[i] = wn[i - 1] * g % MOD;
return n;
}
void NTT(LL a[], int n, int f) {
FOR (i, 0, n) if (i < rev[i])
std::swap(a[i], a[rev[i]]);
for (int k = 1; k < n; k <<= 1) {
for (int i = 0; i < n; i += (k << 1)) {
int t = n / (k << 1);
FOR (j, 0, k) {
LL w = f == 1 ? wn[t * j] : wn[n - t * j];
LL x = a[i + j];
LL y = a[i + j + k] * w % MOD;
a[i + j] = (x + y) % MOD;
a[i + j + k] = (x - y + MOD) % MOD;
}
}
}
if (f == -1) {
LL ninv = get_inv(n, MOD);
FOR (i, 0, n)
a[i] = a[i] * ninv % MOD;
}
}
- n 需补成 2 的幂 (n 必须超过 a 和 b 的最高指数之和)
typedef double LD;
const LD PI = acos(-1);
struct C {
LD r, i;
C(LD r = 0, LD i = 0): r(r), i(i) {}
};
C operator + (const C& a, const C& b) {
return C(a.r + b.r, a.i + b.i);
}
C operator - (const C& a, const C& b) {
return C(a.r - b.r, a.i - b.i);
}
C operator * (const C& a, const C& b) {
return C(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r);
}
void FFT(C x[], int n, int p) {
for (int i = 0, t = 0; i < n; ++i) {
if (i > t) swap(x[i], x[t]);
for (int j = n >> 1; (t ^= j) < j; j >>= 1);
}
for (int h = 2; h <= n; h <<= 1) {
C wn(cos(p * 2 * PI / h), sin(p * 2 * PI / h));
for (int i = 0; i < n; i += h) {
C w(1, 0), u;
for (int j = i, k = h >> 1; j < i + k; ++j) {
u = x[j + k] * w;
x[j + k] = x[j] - u;
x[j] = x[j] + u;
w = w * wn;
}
}
}
if (p == -1)
FOR (i, 0, n)
x[i].r /= n;
}
void conv(C a[], C b[], int n) {
FFT(a, n, 1);
FFT(b, n, 1);
FOR (i, 0, n)
a[i] = a[i] * b[i];
FFT(a, n, -1);
}
$C_k=\sum_{i \oplus j=k} A_i B_j$ - FWT 完后需要先模一遍
template<typename T>
void fwt(LL a[], int n, T f) {
for (int d = 1; d < n; d *= 2)
for (int i = 0, t = d * 2; i < n; i += t)
FOR (j, 0, d)
f(a[i + j], a[i + j + d]);
}
void AND(LL& a, LL& b) { a += b; }
void OR(LL& a, LL& b) { b += a; }
void XOR (LL& a, LL& b) {
LL x = a, y = b;
a = (x + y) % MOD;
b = (x - y + MOD) % MOD;
}
void rAND(LL& a, LL& b) { a -= b; }
void rOR(LL& a, LL& b) { b -= a; }
void rXOR(LL& a, LL& b) {
static LL INV2 = (MOD + 1) / 2;
LL x = a, y = b;
a = (x + y) * INV2 % MOD;
b = (x - y + MOD) * INV2 % MOD;
}
- FWT 子集卷积
a[popcount(x)][x] = A[x]
b[popcount(x)][x] = B[x]
fwt(a[i]) fwt(b[i])
c[i + j][x] += a[i][x] * b[j][x]
rfwt(c[i])
ans[x] = c[popcount(x)][x]
LD simpson(LD l, LD r) {
LD c = (l + r) / 2;
return (f(l) + 4 * f(c) + f(r)) * (r - l) / 6;
}
LD asr(LD l, LD r, LD eps, LD S) {
LD m = (l + r) / 2;
LD L = simpson(l, m), R = simpson(m, r);
if (fabs(L + R - S) < 15 * eps) return L + R + (L + R - S) / 15;
return asr(l, m, eps / 2, L) + asr(m, r, eps / 2, R);
}
LD asr(LD l, LD r, LD eps) { return asr(l, r, eps, simpson(l, r)); }
- FWT
template<typename T>
void fwt(LL a[], int n, T f) {
for (int d = 1; d < n; d *= 2)
for (int i = 0, t = d * 2; i < n; i += t)
FOR (j, 0, d)
f(a[i + j], a[i + j + d]);
}
auto f = [](LL& a, LL& b) { // xor
LL x = a, y = b;
a = (x + y) % MOD;
b = (x - y + MOD) % MOD;
};
LL mul(LL a, LL b, LL m) {
LL ret = 0;
while (b) {
if (b & 1) {
ret += a;
if (ret >= m) ret -= m;
}
a += a;
if (a >= m) a -= m;
b >>= 1;
}
return ret;
}
- O(1)
LL mul(LL u, LL v, LL p) {
return (u * v - LL((long double) u * v / p) * p + p) % p;
}
LL mul(LL u, LL v, LL p) { // 卡常
LL t = u * v - LL((long double) u * v / p) * p;
return t < 0 ? t + p : t;
}
- 如果模数是素数,则可在函数体内加上
n %= MOD - 1;
(费马小定理)。
LL bin(LL x, LL n, LL MOD) {
LL ret = MOD != 1;
for (x %= MOD; n; n >>= 1, x = x * x % MOD)
if (n & 1) ret = ret * x % MOD;
return ret;
}
- 防爆 LL
- 前置模板:快速乘
LL bin(LL x, LL n, LL MOD) {
LL ret = MOD != 1;
for (x %= MOD; n; n >>= 1, x = mul(x, x, MOD))
if (n & 1) ret = mul(ret, x, MOD);
return ret;
}
-
n - 方程个数,m - 变量个数, a 是 n * (m + 1) 的增广矩阵,free 是否为自由变量
-
返回自由变量个数,-1 无解
-
浮点数版本
typedef double LD;
const LD eps = 1E-10;
const int maxn = 2000 + 10;
int n, m;
LD a[maxn][maxn], x[maxn];
bool free_x[maxn];
inline int sgn(LD x) { return (x > eps) - (x < -eps); }
int gauss(LD a[maxn][maxn], int n, int m) {
memset(free_x, 1, sizeof free_x); memset(x, 0, sizeof x);
int r = 0, c = 0;
while (r < n && c < m) {
int m_r = r;
FOR (i, r + 1, n)
if (fabs(a[i][c]) > fabs(a[m_r][c])) m_r = i;
if (m_r != r)
FOR (j, c, m + 1)
swap(a[r][j], a[m_r][j]);
if (!sgn(a[r][c])) {
a[r][c] = 0;
++c;
continue;
}
FOR (i, r + 1, n)
if (a[i][c]) {
LD t = a[i][c] / a[r][c];
FOR (j, c, m + 1) a[i][j] -= a[r][j] * t;
}
++r; ++c;
}
FOR (i, r, n)
if (sgn(a[i][m])) return -1;
if (r < m) {
FORD (i, r - 1, -1) {
int f_cnt = 0, k = -1;
FOR (j, 0, m)
if (sgn(a[i][j]) && free_x[j]) {
++f_cnt;
k = j;
}
if(f_cnt > 0) continue;
LD s = a[i][m];
FOR (j, 0, m)
if (j != k) s -= a[i][j] * x[j];
x[k] = s / a[i][k];
free_x[k] = 0;
}
return m - r;
}
FORD (i, m - 1, -1) {
LD s = a[i][m];
FOR (j, i + 1, m)
s -= a[i][j] * x[j];
x[i] = s / a[i][i];
}
return 0;
}
- 数据
3 4
1 1 -2 2
2 -3 5 1
4 -1 1 5
5 0 -1 7
// many
3 4
1 1 -2 2
2 -3 5 1
4 -1 -1 5
5 0 -1 0 2
// no
3 4
1 1 -2 2
2 -3 5 1
4 -1 1 5
5 0 1 0 7
// one
-
前置模板:素数筛
-
带指数
LL factor[30], f_sz, factor_exp[30];
void get_factor(LL x) {
f_sz = 0;
LL t = sqrt(x + 0.5);
for (LL i = 0; pr[i] <= t; ++i)
if (x % pr[i] == 0) {
factor_exp[f_sz] = 0;
while (x % pr[i] == 0) {
x /= pr[i];
++factor_exp[f_sz];
}
factor[f_sz++] = pr[i];
}
if (x > 1) {
factor_exp[f_sz] = 1;
factor[f_sz++] = x;
}
}
- 不带指数
LL factor[30], f_sz;
void get_factor(LL x) {
f_sz = 0;
LL t = sqrt(x + 0.5);
for (LL i = 0; pr[i] <= t; ++i)
if (x % pr[i] == 0) {
factor[f_sz++] = pr[i];
while (x % pr[i] == 0) x /= pr[i];
}
if (x > 1) factor[f_sz++] = x;
}
- 前置模板:素数筛,快速幂,分解质因数
- 要求 p 为质数
LL find_smallest_primitive_root(LL p) {
get_factor(p - 1);
FOR (i, 2, p) {
bool flag = true;
FOR (j, 0, f_sz)
if (bin(i, (p - 1) / factor[j], p) == 1) {
flag = false;
break;
}
if (flag) return i;
}
assert(0); return -1;
}
- 当
$x\geq\phi(p)$ 时有$a^x\equiv a^{x ; mod ; \phi(p) + \phi(p)}\pmod p$ $\mu^2(n)=\sum_{d^2|n} \mu(d)$ $\sum_{d|n} \varphi(d)=n$ -
$\sum_{d|n} 2^{\omega(d)}=\sigma_0(n^2)$ ,其中$\omega$ 是不同素因子个数 $\sum_{d|n} \mu^2(d)=2^{\omega(d)}$
$\sum_{i=1}^n i[gcd(i, n)=1] = \frac {n \varphi(n) + [n=1]}{2}$ $\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)=x]=\sum_d \mu(d) \lfloor \frac n {dx} \rfloor \lfloor \frac m {dx} \rfloor$ $\sum_{i=1}^n \sum_{j=1}^m gcd(i, j) = \sum_{i=1}^n \sum_{j=1}^m \sum_{d|gcd(i,j)} \varphi(d) = \sum_{d} \varphi(d) \lfloor \frac nd \rfloor \lfloor \frac md \rfloor$ -
$S(n)=\sum_{i=1}^n \mu(i)=1-\sum_{i=1}^n \sum_{d|i,d < i}\mu(d) \overset{t=\frac id}{=} 1-\sum_{t=2}^nS(\lfloor \frac nt \rfloor)$ - 利用
$[n=1] = \sum_{d|n} \mu(d)$
- 利用
-
$S(n)=\sum_{i=1}^n \varphi(i)=\sum_{i=1}^n i-\sum_{i=1}^n \sum_{d|i,d<i} \varphi(i)\overset{t=\frac id}{=} \frac {i(i+1)}{2} - \sum_{t=2}^n S(\frac n t)$ - 利用
$n = \sum_{d|n} \varphi(d)$
- 利用
$\sum_{i=1}^n \mu^2(i) = \sum_{i=1}^n \sum_{d^2|n} \mu(d)=\sum_{d=1}^{\lfloor \sqrt n \rfloor}\mu(d) \lfloor \frac n {d^2} \rfloor$ $\sum_{i=1}^n \sum_{j=1}^n gcd^2(i, j)= \sum_{d} d^2 \sum_{t} \mu(t) \lfloor \frac n{dt} \rfloor ^2 \ \overset{x=dt}{=} \sum_{x} \lfloor \frac nx \rfloor ^ 2 \sum_{d|x} d^2 \mu(\frac xd)$ $\sum_{i=1}^n \varphi(i)=\frac 12 \sum_{i=1}^n \sum_{j=1}^n [i \perp j] - 1=\frac 12 \sum_{i=1}^n \mu(i) \cdot\lfloor \frac n i \rfloor ^2-1$
$F_{a+b}=F_{a-1} \cdot F_b+F_a \cdot F_{b+1}$ $F_1+F_3+\dots +F_{2n-1} = F_{2n},F_2 + F_4 + \dots + F_{2n} = F_{2n + 1} - 1$ $\sum_{i=1}^n F_i = F_{n+2} - 1$ $\sum_{i=1}^n F_i^2 = F_n \cdot F_{n+1}$ $F_n^2=(-1)^{n-1} + F_{n-1} \cdot F_{n+1}$ $gcd(F_a, F_b)=F_{gcd(a, b)}$ - 模
$n$ 周期(皮萨诺周期)$\pi(p^k) = p^{k-1} \pi(p)$ $\pi(nm) = lcm(\pi(n), \pi(m)), \forall n \perp m$ $\pi(2)=3, \pi(5)=20$ $\forall p \equiv \pm 1\pmod {10}, \pi(p)|p-1$ $\forall p \equiv \pm 2\pmod {5}, \pi(p)|2p+2$
$(1+ax)^n=\sum_{k=0}^n \binom {n}{k} a^kx^k$ $\dfrac{1-x^{r+1}}{1-x}=\sum_{k=0}^nx^k$ $\dfrac1{1-ax}=\sum_{k=0}^{\infty}a^kx^k$ $\dfrac 1{(1-x)^2}=\sum_{k=0}^{\infty}(k+1)x^k$ $\dfrac1{(1-x)^n}=\sum_{k=0}^{\infty} \binom{n+k-1}{k}x^k$ $e^x=\sum_{k=0}^{\infty}\dfrac{x^k}{k!}$ $\ln(1+x)=\sum_{k=0}^{\infty}\dfrac{(-1)^{k+1}}{k}x^k$
若一个丢番图方程具有以下的形式:$x^2 - ny^2= 1$。且
若
设
**但是:**佩尔方程千万不要去推(虽然推起来很有趣,但结果不一定好看,会是两个式子)。记住佩尔方程结果的形式通常是 $a_n=ka_{n−1}−a_{n−2}$($a_{n−2}$ 前的系数通常是 $−1$)。暴力 / 凑出两个基础解之后加上一个
$|X/G|={\frac {1}{|G|}}\sum _{{g\in G}}|X^{g}|$
注:$X^g$ 是
$|Y^X/G| = \frac{1}{|G|}\sum_{g \in G} m^{c(g)}$
注:用
-
$S$ 多边形面积 -
$a$ 多边形内部点数 -
$b$ 多边形边上点数
$g(n) = \sum_{d|n} f(d) \Leftrightarrow f(n) = \sum_{d|n} \mu (d) g( \frac{n}{d})$ $f(n)=\sum_{n|d}g(d) \Leftrightarrow g(n)=\sum_{n|d} \mu(\frac{d}{n}) f(d)$
$\sum_{i=1}^{n} i^{1} = \frac{n(n+1)}{2} = \frac{1}{2}n^2 +\frac{1}{2} n$ $\sum_{i=1}^{n} i^{2} = \frac{n(n+1)(2n+1)}{6} = \frac{1}{3}n^3 + \frac{1}{2}n^2 + \frac{1}{6}n$ $\sum_{i=1}^{n} i^{3} = \left[\frac{n(n+1)}{2}\right]^{2} = \frac{1}{4}n^4 + \frac{1}{2}n^3 + \frac{1}{4}n^2$ $\sum_{i=1}^{n} i^{4} = \frac{n(n+1)(2n+1)(3n^2+3n-1)}{30} = \frac{1}{5}n^5 + \frac{1}{2}n^4 + \frac{1}{3}n^3 - \frac{1}{30}n$ $\sum_{i=1}^{n} i^{5} = \frac{n^{2}(n+1)^{2}(2n^2+2n-1)}{12} = \frac{1}{6}n^6 + \frac{1}{2}n^5 + \frac{5}{12}n^4 - \frac{1}{12}n^2$
- 错排公式:$D_1=0,D_2=1,D_n=(n-1)(D_{n-1} + D_{n-2})=n!(\frac 1{2!}-\frac 1{3!}+\dots + (-1)^n\frac 1{n!})=\lfloor \frac{n!}e + 0.5 \rfloor$
- 卡塔兰数($n$ 对括号合法方案数,$n$ 个结点二叉树个数,$n\times n$ 方格中对角线下方的单调路径数,凸
$n+2$ 边形的三角形划分数,$n$ 个元素的合法出栈序列数):$C_n=\frac 1{n+1}\binom {2n}n=\frac{(2n)!}{(n+1)!n!}$
URAL 1132
LL q1, q2, w;
struct P { // x + y * sqrt(w)
LL x, y;
};
P pmul(const P& a, const P& b, LL p) {
P res;
res.x = (a.x * b.x + a.y * b.y % p * w) % p;
res.y = (a.x * b.y + a.y * b.x) % p;
return res;
}
P bin(P x, LL n, LL MOD) {
P ret = {1, 0};
for (; n; n >>= 1, x = pmul(x, x, MOD))
if (n & 1) ret = pmul(ret, x, MOD);
return ret;
}
LL Legendre(LL a, LL p) { return bin(a, (p - 1) >> 1, p); }
LL equation_solve(LL b, LL p) {
if (p == 2) return 1;
if ((Legendre(b, p) + 1) % p == 0)
return -1;
LL a;
while (true) {
a = rand() % p;
w = ((a * a - b) % p + p) % p;
if ((Legendre(w, p) + 1) % p == 0)
break;
}
return bin({a, 1}, (p + 1) >> 1, p).x;
}
int main() {
int T; cin >> T;
while (T--) {
LL a, p; cin >> a >> p;
a = a % p;
LL x = equation_solve(a, p);
if (x == -1) {
puts("No root");
} else {
LL y = p - x;
if (x == y) cout << x << endl;
else cout << min(x, y) << " " << max(x, y) << endl;
}
}
}
- 无解返回 -1
- 前置模板:扩展欧几里得
LL CRT(LL *m, LL *r, LL n) {
if (!n) return 0;
LL M = m[0], R = r[0], x, y, d;
FOR (i, 1, n) {
d = ex_gcd(M, m[i], x, y);
if ((r[i] - R) % d) return -1;
x = (r[i] - R) / d * x % (m[i] / d);
// 防爆 LL
// x = mul((r[i] - R) / d, x, m[i] / d);
R += x * M;
M = M / d * m[i];
R %= M;
}
return R >= 0 ? R : R + M;
}
- 预处理逆元
- 预处理组合数
-
$\sum_{i=0}^n i^k = \frac{1}{k+1} \sum_{i=0}^k \binom{k+1}{i} B_{k+1-i} (n+1)^i$ . - 也可以
$\sum_{i=0}^n i^k = \frac{1}{k+1} \sum_{i=0}^k \binom{k+1}{i} B^+_{k+1-i} n^i$ 。区别在于$B^+_1 =1/2$ 。(心态崩了)
namespace Bernoulli {
const int M = 100;
LL inv[M] = {-1, 1};
void inv_init(LL n, LL p) {
FOR (i, 2, n)
inv[i] = (p - p / i) * inv[p % i] % p;
}
LL C[M][M];
void init_C(int n) {
FOR (i, 0, n) {
C[i][0] = C[i][i] = 1;
FOR (j, 1, i)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
LL B[M] = {1};
void init() {
inv_init(M, MOD);
init_C(M);
FOR (i, 1, M - 1) {
LL& s = B[i] = 0;
FOR (j, 0, i)
s += C[i + 1][j] * B[j] % MOD;
s = (s % MOD * -inv[i + 1] % MOD + MOD) % MOD;
}
}
LL p[M] = {1};
LL go(LL n, LL k) {
n %= MOD;
if (k == 0) return n;
FOR (i, 1, k + 2)
p[i] = p[i - 1] * (n + 1) % MOD;
LL ret = 0;
FOR (i, 1, k + 2)
ret += C[k + 1][i] * B[k + 1 - i] % MOD * p[i] % MOD;
ret = ret % MOD * inv[k + 1] % MOD;
return ret;
}
}
- 要求有基本解,也就是 x 为零向量可行
- v 要初始化为 0,n 表示向量长度,m 表示约束个数
// min{ b x } / max { c x }
// A x >= c / A x <= b
// x >= 0
namespace lp {
int n, m;
double a[M][N], b[M], c[N], v;
void pivot(int l, int e) {
b[l] /= a[l][e];
FOR (j, 0, n) if (j != e) a[l][j] /= a[l][e];
a[l][e] = 1 / a[l][e];
FOR (i, 0, m)
if (i != l && fabs(a[i][e]) > 0) {
b[i] -= a[i][e] * b[l];
FOR (j, 0, n)
if (j != e) a[i][j] -= a[i][e] * a[l][j];
a[i][e] = -a[i][e] * a[l][e];
}
v += c[e] * b[l];
FOR (j, 0, n) if (j != e) c[j] -= c[e] * a[l][j];
c[e] = -c[e] * a[l][e];
}
double simplex() {
while (1) {
v = 0;
int e = -1, l = -1;
FOR (i, 0, n) if (c[i] > eps) { e = i; break; }
if (e == -1) return v;
double t = INF;
FOR (i, 0, m)
if (a[i][e] > eps && t > b[i] / a[i][e]) {
t = b[i] / a[i][e];
l = i;
}
if (l == -1) return INF;
pivot(l, e);
}
}
}
- 模数为素数
LL BSGS(LL a, LL b, LL p) { // a^x = b (mod p)
a %= p;
if (!a && !b) return 1;
if (!a) return -1;
static map<LL, LL> mp; mp.clear();
LL m = sqrt(p + 1.5);
LL v = 1;
FOR (i, 1, m + 1) {
v = v * a % p;
mp[v * b % p] = i;
}
LL vv = v;
FOR (i, 1, m + 1) {
auto it = mp.find(vv);
if (it != mp.end()) return i * m - it->second;
vv = vv * v % p;
}
return -1;
}
- 模数可以非素数
LL exBSGS(LL a, LL b, LL p) { // a^x = b (mod p)
a %= p; b %= p;
if (a == 0) return b > 1 ? -1 : b == 0 && p != 1;
LL c = 0, q = 1;
while (1) {
LL g = __gcd(a, p);
if (g == 1) break;
if (b == 1) return c;
if (b % g) return -1;
++c; b /= g; p /= g; q = a / g * q % p;
}
static map<LL, LL> mp; mp.clear();
LL m = sqrt(p + 1.5);
LL v = 1;
FOR (i, 1, m + 1) {
v = v * a % p;
mp[v * b % p] = i;
}
FOR (i, 1, m + 1) {
q = q * v % p;
auto it = mp.find(q);
if (it != mp.end()) return i * m - it->second + c;
}
return -1;
}
for (LL l = 1, v, r; l <= N; l = r + 1) {
v = N / l; r = N / v;
}
- Nim 游戏:每轮从若干堆石子中的一堆取走若干颗。先手必胜条件为石子数量异或和非零。
- 阶梯 Nim 游戏:可以选择阶梯上某一堆中的若干颗向下推动一级,直到全部推下去。先手必胜条件是奇数阶梯的异或和非零(对于偶数阶梯的操作可以模仿)。
- Anti-SG:无法操作者胜。先手必胜的条件是:
- SG 不为 0 且某个单一游戏的 SG 大于 1 。
- SG 为 0 且没有单一游戏的 SG 大于 1。
- Every-SG:对所有单一游戏都要操作。先手必胜的条件是单一游戏中的最大 step 为奇数。
- 对于终止状态 step 为 0
- 对于 SG 为 0 的状态,step 是最大后继 step +1
- 对于 SG 非 0 的状态,step 是最小后继 step +1
- 树上删边:叶子 SG 为 0,非叶子结点为所有子结点的 SG 值加 1 后的异或和。
尝试:
- 打表找规律
- 寻找一类必胜态(如对称局面)
- 直接博弈 dp