P2714 四元组统计
考虑类似于SOSDP的方法,统计超集的大小,在这个集合内任选4个数,可以算出方案数,保证他们的 $\gcd$ 为 $x$ 的倍数,再差分回去,即为答案。
查看代码
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
| #include <cstdio> using namespace std; template <class Type> void read (Type &x) { char c; bool flag = false; while ((c = getchar()) < '0' || c > '9') flag |= c == '-'; x = c - '0'; while ((c = getchar()) >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0'; if (flag) x = ~x + 1; } template <class Type, class ...Rest> void read (Type &x, Rest &...y) { read(x); read(y...); } template <class Type> void write (Type x) { if (x < 0) putchar('-'), x = ~x + 1; if (x > 9) write(x / 10); putchar('0' + x % 10); } typedef long long LL; const int N = 1e4 + 10; int n; LL f[N]; bool vis[N]; int cnt, p[N]; void init () { vis[1] = true; for (int i = 2; i < N; ++i) { if (!vis[i]) p[++cnt] = i; for (int j = 1; j <= cnt && i * p[j] < N; ++j) { vis[i * p[j]] = true; if (i % p[j] == 0) break; } } } int main () { init(); while (~scanf("%d", &n)) { for (int i = 1; i < N; ++i) f[i] = 0; for (int a; n; --n) read(a), ++f[a]; for (int i = 1; i <= cnt; ++i) for (int j = (N - 1) / p[i]; j; --j) f[j] += f[p[i] * j]; for (int i = 1; i < N; ++i) f[i] = f[i] * (f[i] - 1) * (f[i] - 2) * (f[i] - 3) / 24; for (int i = 1; i <= cnt; ++i) for (int j = 1; p[i] * j < N; ++j) f[j] -= f[p[i] * j]; write(f[1]), puts(""); } return 0; }
|