【题目链接】
【思路要点】
- 注意到答案是 O ( L o g M ) O(LogM) O(LogM) 级别的。
- 对于每一个点 i i i 我们暴力维护其 d p dp dp 值 d p i dp_i dpi 以及能够转移到 i i i 的各个位置的中 d p dp dp 值为 j j j 的位置数 c n t i , j cnt_{i,j} cnti,j 。
- 令 f ( x ) f(x) f(x) 表示 x x x 的因子个数。
- 对于操作 0 x 0\ x 0 x ,其时间复杂度为 O ( M x + L o g M ) O(\frac{M}{x}+LogM) O(xM+LogM) 。
- 对于操作 1 x 1\ x 1 x ,其时间复杂度为 O ( ∑ i / x f ( i ) + f ( x ) ∗ L o g M ) O(\sum_{i/x}f(i)+f(x)*LogM) O(∑i/xf(i)+f(x)∗LogM) 。
- 对于操作 2 2 2 ,其时间复杂度为 O ( 1 ) O(1) O(1) 。
- 对于操作 3 3 3 ,其时间复杂度为 O ( ∑ i / x f ( i ) + f ( x ) ∗ L o g M ) O(\sum_{i/x}f(i)+f(x)*LogM) O(∑i/xf(i)+f(x)∗LogM) 。
- 由于题目保证 C = 10 C=10 C=10 ,总时间复杂度是可以接受的。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXLOG = 25; const int MAXN = 1e6 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m, q, l, r, a[MAXN], ans[MAXLOG]; int pos[MAXN], dp[MAXN], cnt[MAXN][MAXLOG]; void answer() { for (int i = MAXLOG - 1; i >= 0; i--) if (ans[i]) { printf("%d %d\n", i, ans[i]); return; } assert(false); } void clear(int x) { memset(cnt[x], 0, sizeof(cnt[x])); dp[x] = 1, cnt[x][1] = 1; } void pushfront(int x) { clear(x); pos[x] = --l, a[l] = x; for (int i = 2 * x; i <= m; i += x) if (pos[i]) cnt[x][dp[i] + 1]++; for (int i = MAXLOG - 1; i >= 1; i--) if (cnt[x][i]) { dp[x] = i; break; } ans[dp[x]]++; } void popfront() { int x = a[l++]; ans[dp[x]]--, pos[x] = 0; } int val[MAXN], old[MAXN], tot; void update(int x, int val, int d) { ans[val] += d; for (int i = 1; i * i <= x; i++) if (x % i == 0) { if (pos[i] < pos[x]) cnt[i][val + 1] += d; if (i * i != x && pos[x / i] < pos[x]) cnt[x / i][val + 1] += d; } } void pushback(int x) { clear(x); pos[x] = ++r, a[r] = x; tot = 0; for (int i = 1; i * i <= x; i++) if (x % i == 0) { val[++tot] = i, old[i] = dp[i]; if (i * i != x) val[++tot] = x / i, old[x / i] = dp[x / i]; } sort(val + 1, val + tot + 1); update(x, dp[x], 1); for (int j = tot - 1; j >= 1; j--) { int x = val[j]; for (int i = MAXLOG - 1; i >= 1; i--) if (cnt[x][i]) { dp[x] = i; break; } if (!pos[x] || old[x] == dp[x]) continue; update(x, old[x], -1); update(x, dp[x], 1); } } void popback() { int x = a[r--]; tot = 0; for (int i = 1; i * i <= x; i++) if (x % i == 0) { val[++tot] = i, old[i] = dp[i]; if (i * i != x) val[++tot] = x / i, old[x / i] = dp[x / i]; } sort(val + 1, val + tot + 1); update(x, dp[x], -1); for (int j = tot - 1; j >= 1; j--) { int x = val[j]; for (int i = MAXLOG - 1; i >= 1; i--) if (cnt[x][i]) { dp[x] = i; break; } if (!pos[x] || old[x] == dp[x]) continue; update(x, old[x], -1); update(x, dp[x], 1); } pos[x] = 0; } int main() { read(n), read(m), read(q); l = 5e5, r = l - 1; for (int i = 1; i <= n; i++) { int x; read(x); pushback(x); } answer(); for (int i = 1; i <= q; i++) { int opt, x; read(opt); if (opt <= 1) { read(x); if (opt == 0) pushfront(x); else pushback(x); } else { if (opt == 2) popfront(); else popback(); } answer(); } return 0; }