给出 \(k,m\),求方程 \(k^x=1\pmod{m}\) 的 \(x\) 的最小正整数解。
若无解,输出 No Solution
。
多测,\(1 \leq T \leq 10^3,2 \leq m,k\leq 10^9\)。
无解:\(\gcd(k,m) \ne 1\)。
套个 BSGS
\(\mathcal O(\sqrt{n})\) 求即可。
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int, int> #define mp(a, b) make_pair(a, b) int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } template<typename T> T exgcd(T a, T b, T &x, T &y) { if(!b) return x = 1, y = 0, a; int d = exgcd(b, a % b, y, x); return y -= a / b * x, d; } int gcd(int a, int b) { if(!b) return a; return gcd(b, a % b); } inline int BSGS(int a, int b, int m) { static unordered_map<int, int> buk; buk.clear(); int S = sqrt(m - 1) + 1; int A = 1, f = -1; for(int i = 0; i < S; ++i) { buk[b * A % m] = i; A = A * a % m; } int C = 1; for(int i = 1; i <= S; ++i) { C = C * A % m; auto it = buk.find(C); if(it != buk.end()) return i * S - it->second; } return -1; } int a, b, m; signed main() { int t = read(); while(t--) { m = read(), a = read(); a %= m; if(__gcd(a, m) != 1 || a == 0) { puts("No Solution"); continue; } int ans = BSGS(a, 1, m); write(ans), putchar('\n'); } return 0; }
给出 \(S,p,m,q,n\),求方程 \(p+mx \equiv q+nx \pmod{S}\) 的最小 \(x\) 的正整数解。
\(1 \leq p,q,m,n,S < 2^{31}\)。
套个 exgcd
即可。
#include <bits/stdc++.h> using namespace std; #define int long long int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } int s, p, m, q, n, x, y; int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } int exgcd(int a, int b, int &x, int &y) { if (b == 0) { x = 1, y = 0; return a; } int g = exgcd(b, a % b, x, y); int t = x; x = y; y = t - a / b * y; return g; } signed main() { s = read(), p = read(), m = read(), q = read(), n = read(); int a = ((n - m) % s + s) % s, c = ((p - q) % s + s) % s; if (c % gcd(a, s) != 0) { puts("Cannot Get The Secret!"); return 0; } int g = exgcd(a, s, x, y); x *= (c / gcd(a, s)); int kkk = s / g; x = (x % kkk + kkk) % kkk; if (x == 0) x += kkk; write(x); return 0; }
给你 \(n,m\),表示有 \(m\) 个询问,每组询问形如 l,r
,表示求 \(\forall l \leq j \leq r,\max(n \bmod j)\)。
\(1 \leq n \leq 10^{10},1 \leq m \leq 10^5\)。
显然的数论分块。
但显然不能边数论分块边回答询问。
考虑将数论分块预处理好。
根据 \(n \bmod j=n-\lfloor\frac{n}{j}\rfloor \cdot j\)。
可转换为求 \(\lfloor\frac{n}{j}\rfloor \cdot j\) 的最小值。
根据 \(\lfloor\frac{n}{j}\rfloor\) 的值相同的一个块内,最小值显然处于左端点。
所以上述做法正确性显然。
细节:
\(l\) 如果不处于它块的左端点,那么它这个块就需要特判一下。
#include <bits/stdc++.h> using namespace std; #define int long long inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } inline void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } int n, m, sq; const int _ = 4e5 + 7; int tot, p[_], q[_]; int a[_][22]; int lg[_]; void update() { for (int j = 1; (1 << j) <= tot; j++) { for (int i = 1; i + (1 << j) - 1 <= tot; i++) { a[i][j] = min(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]); } } } int query(int l, int r) { if (l > r) return 0; int t = lg[r - l + 1] - 1; return min(a[l][t], a[r - (1 << t) + 1][t]); } int erfenl(int x) { int l = 1, r = tot, mid; while(l <= r) { mid = (l + r) >> 1; // cout << mid << "\n"; if(x >= p[mid] && x <= q[mid]) { if(x > p[mid]) return mid + 1; return mid; } else if(x < p[mid]) { r = mid - 1; } else if(x > q[mid]) { l = mid + 1; } } } int erfenr(int x) { int l = 1, r = tot, mid, ans = 0; while(l <= r) { mid = (l + r) >> 1; if(x >= p[mid] && x <= q[mid]) { return mid; } else if(x < p[mid]) { r = mid - 1; } else { l = mid + 1; } } } signed main() { // freopen("ex.in", "r", stdin); // freopen("2.out", "w", stdout); for(int i = 0; i < _; ++i) for(int j = 0; j < 21; ++j) a[i][j] = 1e10 + 7; n = read(), m = read(); sq = sqrt(n); for(int i = 1, j; i <= n; i = j + 1) { j = n / (n / i); p[++tot] = i, q[tot] = j; a[tot][0] = (n / i) * p[tot]; } for (int i = 1; i <= tot; ++i) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); update(); while(m--) { int l = read(), r = read(); if(l > r) swap(l, r); int L = erfenl(l), R = erfenr(r); if(L > R) { write(n - (n / l) * l); putchar('\n'); continue; } write(n - query(L, R)); putchar('\n'); } return 0; }
区间加,区间查询 \(\ge c\) 的数的个数。
分块。
区间加用 lazytag
维护。
查询二分预处理即可。
#include <bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } inline void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } const int _ = 1e6 + 7; int n, q; int a[_], l[_], r[_], d[_], bel[_], lz[_]; int blo, tot; void cg(int x) { for(int i = l[bel[x]]; i <= r[bel[x]]; ++i) d[i] = a[i]; sort(d + l[bel[x]], d + r[bel[x]] + 1); } void change(int x, int y, int k) { if(bel[x] == bel[y]) { for(int i = x; i <= y; ++i) a[i] += k; cg(x); } else { for(int i = x; i <= r[bel[x]]; ++i) a[i] += k; cg(x); for(int i = l[bel[y]]; i <= y; ++i) a[i] += k; cg(y); for(int i = bel[x] + 1; i <= bel[y] - 1; ++i) lz[i] += k; } } int query(int x, int y, int k) { int ans = 0; if(bel[x] == bel[y]) { for(int i = x; i <= y; ++i) if(lz[bel[x]] + a[i] >= k) ans++; return ans; } else { for(int i = x; i <= r[bel[x]]; ++i) if(lz[bel[x]] + a[i] >= k) ans++; for(int i = l[bel[y]]; i <= y; ++i) if(lz[bel[y]] + a[i] >= k) ans++; for(int i = bel[x] + 1; i <= bel[y] - 1; ++i) ans += r[i] - (lower_bound(d + l[i], d + r[i] + 1, k - lz[i]) - d) + 1; return ans; } } signed main() { n = read(), q = read(); for(int i = 1; i <= n; ++i) a[i] = read(); blo = sqrt(n), tot = n / blo; if(n % blo) tot++; for(int i = 1; i <= n; ++i) bel[i] = (i - 1) / blo + 1, d[i] = a[i]; for(int i = 1; i <= tot; ++i) l[i] = (i - 1) * blo + 1, r[i] = i * blo; r[tot] = n; for(int i = 1; i <= tot; ++i) sort(d + l[i], d + r[i] + 1); while(q--) { char s[10]; scanf("%s", s); int x = read(), y = read(), c = read(); if(x > y) swap(x, y); if(s[0] == 'M') { change(x, y, c); } else { write(query(x, y, c)); putchar('\n'); } } return 0; }