int prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19}; int n, p; structnode { int v, p, s; node() : v(0), p(-1), s(0) {} voidget(){ int x = v; for (int i = 1; i <= 8; i++) { if (x % prime[i]) continue; s |= 1 << (i - 1); while (x % prime[i] == 0) x /= prime[i]; } if (x != 1) p = x; } } a[N]; int dp[N][N], f[N][N], g[N][N];
void _main() { cin >> n >> p; for (int i = 2; i <= n; i++) a[i].v = i, a[i].get(); sort(a + 2, a + n + 1, [](const node& x, const node& y) -> bool { return x.p < y.p; }); dp[0][0] = 1; for (int i = 2; i <= n; i++) { if (i == 2 || a[i].p != a[i - 1].p || a[i].p == -1) { // 新连续段 memcpy(f, dp, sizeof(f)), memcpy(g, dp, sizeof(g)); } #define add(x, y) ((x) += (y), (x) >= p ? (x) -= p : (x)) #define madd(x, y) ((x) + (y) >= p ? (x) + (y) - p : (x) + (y)) #define msub(x, y) ((x) - (y) < 0 ? (x) - (y) + p : (x) - (y)) for (int s = M - 1; s >= 0; s--) { for (int t = M - 1; t >= 0; t--) { if (s & t) continue; if ((a[i].s & t) == 0) add(f[a[i].s | s][t], f[s][t]); if ((a[i].s & s) == 0) add(g[s][a[i].s | t], g[s][t]); } } if (i == n || a[i].p != a[i + 1].p || a[i].p == -1) { // 下一个点是新连续段 for (int s = 0; s < M; s++) { for (int t = 0; t < M; t++) { if (s & t) continue; dp[s][t] = msub(madd(f[s][t], g[s][t]), dp[s][t]); } } } } int res = 0; for (int s = 0; s < M; s++) { for (int t = 0; t < M; t++) { if (s & t) continue; add(res, dp[s][t]); } } cout << res; }