1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| #include <bits/stdc++.h>
using u64 = uint64_t;
const int kMaxP = 4e5 + 5, kMaxN = 1e6 + 5;
int p, n, rt; int op[kMaxN], a[kMaxN], g[kMaxP], cnt[kMaxP]; u64 pw[kMaxP * 2]; bool vis[kMaxP];
struct BIT { u64 c[kMaxP * 4]; void upd(int x, u64 v) { for (++x; x <= 2 * p + 1; x += x & -x) c[x] += v; } u64 qry(int x) { u64 ret = 0; for (++x; x; x -= x & -x) ret += c[x]; return ret; } u64 qry(int l, int r) { return l <= r ? (qry(r) - qry(l - 1)) : 0; } } bit1, bit2;
int findrt(int p) { g[0] = -1, g[1] = 0; for (int i = 2; i <= p - 1; ++i) { bool fl = 1; for (int j = 1, mul = i; j < p - 1; ++j, mul = 1ll * mul * i % p) { if (mul == 1) { fl = 0; break; } g[mul] = j; } if (fl) return i; } return 1; }
int findpos(int lst, int x) { int L = lst, R = p - 1, res = p - 1; while (L + 1 < R) { int mid = (L + R) >> 1; if (bit1.qry(lst + 1, mid) * pw[x] != bit1.qry(lst + x + 1, mid + x)) R = res = mid; else L = mid; } return res; }
int findpos1(int lst, int x) { int L = lst, R = p - 1, res = p - 1; while (L + 1 < R) { int mid = (L + R) >> 1; if (bit2.qry(lst + 1, mid) * pw[x] != bit1.qry(lst + x + 1, mid + x)) R = res = mid; else L = mid; } return res; }
void dickdreamer() { std::cin >> p >> n; rt = findrt(p); int ans = 0; bool fl = 0; for (int i = 1; i <= n; ++i) { std::cin >> op[i] >> a[i]; a[i] = g[a[i]]; if (!~a[i]) ans |= 1; if (op[i] == 1) { if (~a[i]) ++cnt[a[i]]; } else { fl = 1; } } if (!fl) return void(std::cout << p - 1 << '\n'); pw[0] = 1; for (int i = 1; i <= 2 * p + 1; ++i) pw[i] = 13331ull * pw[i - 1]; vis[0] = vis[p - 1] = 1, bit1.upd(0, pw[0]), bit1.upd(p - 1, pw[p - 1]); for (int i = 1; i < p - 1; ++i) { for (int j = 1; j <= cnt[i]; ++j) { int now = -1; std::vector<int> vec; for (; now < p - 1;) { now = findpos(now, i); if (now < p - 1 && vis[now]) vec.emplace_back(now); } for (auto x : vec) { int r = (x + i) % (p - 1); assert(vis[x] && !vis[r]); vis[r] = vis[r + p - 1] = 1, bit1.upd(r, pw[r]), bit1.upd(r + p - 1, pw[r + p - 1]); } } } for (int i = 0; i <= 2 * p + 1; ++i) bit2.c[i] = bit1.c[i], vis[i] = 0; memset(bit1.c, 0, sizeof(bit1.c)); for (int i = 1; i <= n; ++i) { if (op[i] == 1 || !~a[i]) continue; int now = -1; std::vector<int> vec; for (; now < p - 1;) { now = findpos1(now, a[i]); if (now < p - 1 && !vis[(now + a[i]) % (p - 1)]) vec.emplace_back(now); } for (auto x : vec) { int r = (x + a[i]) % (p - 1); assert(!vis[r]); vis[r] = vis[r + p - 1] = 1, bit1.upd(r, pw[r]), bit1.upd(r + p - 1, pw[r + p - 1]); } } for (int i = 0; i < p - 1; ++i) ans += vis[i]; std::cout << p - ans << '\n'; }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; while (T--) dickdreamer(); return 0; }
|