constint N = 5010; int primes[N], cnt; int sum[N]; bool st[N];
voidinit(int n){ for (int i = 2; i <= n; i++) { if (!st[i]) primes[cnt++] = i; for (int j = 0; primes[j] <= n/i; j++) { st[primes[j]*i] = true; if (i % primes[j] == 0) break; } } }
vector<int> mul(vector<int>& a, int b){ vector<int> c; int t = 0; for (int i = 0; i < a.size() || t; i++) { if (i < a.size()) t += a[i] * b; c.push_back(t%10); t /= 10; } while (c.size() && c.back() == 0) c.pop_back(); return c; }
intfactorize(int n, int p){ int res = 0; while (n) { res += n/p; n /= p; } return res; }
intmain(){ int a, b; scanf("%d%d", &a, &b); init(max(a, b)); vector<int> res; res.push_back(1); for (int i = 0; i < cnt; i++) { int p = primes[i]; int s = factorize(a, p) - factorize(a-b, p) - factorize(b, p); while (s--) res = mul(res, p); } for (int i = res.size()-1; i >= 0; i--) { printf("%d", res[i]); } puts(""); return0; }
不定方程的整数解
对于函数 g(x)=xx mod 1000,方程 a1+a2+⋯+ak−1+ak=g(x),其中 k∈N∗,x 是正整数,x,k 是给定的数。求这个关于 ai 不定方程的正整数解组数。
typedeflonglong LL; constint N = 2000010; int S[N]; int n, c;
LL C(LL x, int k){ if (k == 1) return x; elseif (k == 2) return x * (x-1) / 2; elseif (k == 3) return x * (x-1) * (x-2) / 6; elsereturn-1; }
intmain(){ scanf("%d%d", &n, &c); for (int i = 0; i < n; i++) { int p; scanf("%d", &p); ++p; S[p]++, S[p+c]++; }
for (int i = 1; i <= 2*c; i++) S[i] += S[i-1]; LL res = C(n, 3);
// 枚举每个位置 for (int i = 1; i <= c; i++) { int y = S[i] - S[i-1]; // i+1 ~ i + c/2 int x = S[i+c/2] - S[i]; res -= C(y, 1)*C(x, 2) + C(y, 2)*C(x, 1) + C(y, 3); } // 直径被重复计算了 if (c % 2 == 0) { for (int i = 1; i <= c/2; i++) { int y = S[i] - S[i-1]; int x = S[i+c/2] - S[i+c/2-1]; res += C(y, 1)*C(x, 2) + C(y, 2)*C(x, 1); } } printf("%lld\n", res); return0; }
序列统计
给定三个整数 N,L,R,统计长度在 1 到 N 之间,元素大小都在 L 到 R 之间的单调不降序列的数量。
LL inv(LL a){ int k = mod-2; LL res = 1; while (k) { if (k & 1) res = res * a % mod; a = a * a % mod; k >>= 1; } return res; }
LL C(int a, int b){ LL up = 1, down = 1; for (int i = 1, j = a; i <= b; i++, j--) { up = up * j % mod; down = down * i % mod; } return up * inv(down) % mod; }
LL lucas(LL a, LL b){ if (a < mod && b < mod) returnC(a, b); returnlucas(a/mod, b/mod) * C(a%mod, b%mod) % mod; }
intmain(){ int T, n, l, r; scanf("%d", &T); while (T--) { scanf("%d%d%d", &n, &l, &r); printf("%d\n", ((lucas(r-l+n+1, r-l+1)-1)+mod)%mod); } return0; }
这里不要把 inv 写到求组合数的循环里面了,会大大加大复杂度,统一到循环结束后再乘。
卡特兰数
给定 n 个 0 和 n 个 1,它们将按照某种顺序排成长度为 2n 的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列有多少个。
// n+m 最大 10000 constint N = 10010; int primes[N], cnt; bool st[N]; int n, m;
voidgetprimes(int n){ for (int i = 2; i <= n; i++) { if (!st[i]) primes[cnt++] = i; for (int j = 0; primes[j] <= n/i; j++) { st[primes[j] * i] = true; if (i % primes[j] == 0) break; } } }
intfactorize(int n, int p){ int res = 0; while (n) { res += n/p; n /= p; } return res; }
vector<int> mul(const vector<int>& a, int b){ vector<int> res; int t = 0; for (int i = 0; i < a.size() || t; i++) { if (i < a.size()) t += a[i]*b; res.push_back(t % 10); t /= 10; } return res; }
vector<int> sub(const vector<int>& a, const vector<int> &b){ vector<int> res; for (int i = 0, t = 0; i < a.size(); i++) { t = a[i] - t; if (i < b.size()) t -= b[i]; res.push_back((t+10)%10); if (t < 0) t = 1; else t = 0; } while (res.size() && res.back() == 0) res.pop_back(); return res; }
vector<int> C(int a, int b){ vector<int> res; res.push_back(1); for (int i = 0; i < cnt; i++) { int p = primes[i]; int s = factorize(a, p) - factorize(a-b, p) - factorize(b, p); while (s--) res = mul(res, p); } return res; }
intmain(){ getprimes(N-1); scanf("%d%d", &n, &m); vector<int> res = sub(C(n+m, m), C(n+m, m-1)); for (int i = res.size() - 1; i >= 0; i--) printf("%d", res[i]); puts(""); return0; }
typedeflonglong LL; constint N = 2e6+10; int n, mod; int primes[N], cnt; bool st[N];
voidgetprimes(int n){ for (int i = 2; i <= n; i++) { if (!st[i]) primes[cnt++] = i; for (int j = 0; primes[j] <= n/i; j++) { st[primes[j]*i] = true; if (i % primes[j] == 0) break; } } }
intqmi(int a, int k){ int res = 1; while (k) { if (k & 1) res = (LL)res * a % mod; a = (LL)a * a % mod; k >>= 1; } return res; }
intfactorize(int n, int p){ int cnt = 0; while (n) { cnt += n / p; n /= p; } return cnt; }
intC(int a, int b){ int res = 1; for (int i = 0; i < cnt; i++) { int p = primes[i]; int s = factorize(a, p) - factorize(a-b, p) - factorize(b, p); res = (LL)res * qmi(p, s) % mod; } return res; }
intqmi(int a, int k, int p){ int res = 1; while (k) { if (k & 1) res = (LL)res * a % p; a = (LL)a * a % p; k >>= 1; } return res; }
intC(int a, int b){ // a!/(b!)(a-b)! int fa = 1, fb = 1, fab = 1; for (int i = 2; i <= a; i++) fa = (LL)fa * i % MOD; for (int i = 2; i <= b; i++) fb = (LL)fb * i % MOD; for (int i = 2; i <= a-b; i++) fab = (LL)fab * i % MOD; return (LL)fa*qmi(fb, MOD-2, MOD)*qmi(fab, MOD-2, MOD) % MOD; }
intmain(){ scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) p[i] = i, v[i] = -1; for (int i = 1; i <= n-k+1; i++) scanf("%d", &S[i]); for (int i = 1; i <= n-k; i++) { // j: 下一个区间末尾 int j = i+k; if (S[i] == S[i+1]) p[find(i)] = find(j); } // 先合并所有集合然后再赋值 for (int i = 1; i <= n-k; i++) { int j = i+k; if (S[i] == S[i+1]+1) v[find(i)] = 1, v[find(j)] = 0; elseif (S[i]+1 == S[i+1]) v[find(i)] = 0, v[find(j)] = 1; elseif (S[i] != S[i+1]) exit(-1); } int c0 = 0, c1 = 0; for (int i = 1; i <= k; i++) { if (v[find(i)] == 1) c1++; if (v[find(i)] == 0) c0++; } printf("%d\n", C(k-c0-c1, S[1]-c1)); return0; }