loj#2565. 「SDOI2018」舊試題(反演 三元環計數)
阿新 • • 發佈:2019-02-11
pac bit memset etc uil auto space har open
題意
題目鏈接
Sol
神仙反演題。在洛谷上瘋狂被卡常
Orz shadowice
#include<bits/stdc++.h> #define Pair pair<int, int> #define MP make_pair #define fi first #define se second #define LL long long const int MAXN = 2e5 + 10, mod = 1e9 + 7; using namespace std; template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;} template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;} template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;} template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);} template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;} template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} inline int read() { char c = getchar(); int x = 0, f = 1; 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; } int mu[MAXN], prime[MAXN], vis[MAXN], tot, A, B, C, num, deg[MAXN]; int fa[MAXN], fb[MAXN], fc[MAXN]; vector<LL> di[MAXN]; vector<Pair> v[MAXN];//每個數的質因數分解 struct Edge { LL u, v, w; }E[MAXN * 10]; void GetPrime(int N) { vis[1] = 1; mu[1] = 1; for(int i = 2; i <= N; i++) { if(!vis[i]) prime[++tot] = i, mu[i] = -1; for(int j = 1; j <= tot && i * prime[j] <= N; j++) { vis[i * prime[j]] = 1; if(i % prime[j]) mu[i * prime[j]] = -mu[i]; else {mu[i * prime[j]] = 0; break;} } } for(int i = 1; i <= tot; i++) for(int j = 1; j * prime[i] <= N; j++) di[j * prime[i]].push_back(prime[i]); } void Get(int *a, int N, int X) { for(int i = 1; i <= N; i++) for(int j = i; j <= N; j += i) a[i] += X / j; } LL lcm(int a, int b) { return 1ll * a / __gcd(a, b) * b; } void init() { memset(fa, 0, sizeof(fa)); memset(fb, 0, sizeof(fb)); memset(fc, 0, sizeof(fc)); memset(deg, 0, sizeof(deg)); num = 0; for(int i = 1; i <= A; i++) v[i].clear(); } void Build() { for(int w = 1; w <= A; w++) {//lcm(u, v) = w; if(!mu[w]) continue; int n = di[w].size(); //for(auto x : di[w]) printf("%d ", x); puts(""); for(int sta = 0; sta < (1 << n); sta++) { LL i = 1; for(int b = 0; b < n; b++) if(sta >> b & 1) i *= di[w][b]; for(int s = sta; ; s = sta & (s - 1)) {//tag LL g = 1; for(int b = 0; b < n; b++) if(s >> b & 1) g *= di[w][b]; int j = w * g / i; if(i < j) E[++num] = {i, j, w};// printf("%d\n", num); if(!s) break; } } } } LL fuck(int x, int y, int w) { if(mu[x] == 1) return add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w])); else return (-add(add(mul(mul(fa[w], fb[w]), fc[y]), mul(mul(fa[w], fb[y]), fc[w])), mul(mul(fa[y], fb[w]), fc[w])) + mod) % mod; } LL calc() { // for(int i = 1; i <= A; i++) for(auto &x : v[i])printf("%d %d %d\n", i, x.fi, x.se); for(int i = 1; i <= num; i++) { int x = E[i].u, y = E[i].v; if(deg[x] > deg[y]) swap(x, y); v[y].push_back(MP(x, E[i].w)); } LL ans = 0; for(int a = 1; a <= A; a++) { for(auto &t1 : v[a]) { LL b = t1.fi, w1 = t1.se; for(auto &t2 : v[b]) { LL c = t2.fi, w2 = t2.se, xi = mu[a] * mu[b] * mu[c]; LL w3 = lcm(a, c); if(w3 > A) continue; if(xi == 1) { add2(ans, mul(mul(fa[w1], fb[w2]), fc[w3])); add2(ans, mul(mul(fa[w1], fb[w3]), fc[w2])); add2(ans, mul(mul(fa[w2], fb[w1]), fc[w3])); add2(ans, mul(mul(fa[w2], fb[w3]), fc[w1])); add2(ans, mul(mul(fa[w3], fb[w1]), fc[w2])); add2(ans, mul(mul(fa[w3], fb[w2]), fc[w1])); } else if(xi == -1) { add2(ans, mul(mul(-fa[w1], fb[w2]), fc[w3])); add2(ans, mul(mul(-fa[w1], fb[w3]), fc[w2])); add2(ans, mul(mul(-fa[w2], fb[w1]), fc[w3])); add2(ans, mul(mul(-fa[w2], fb[w3]), fc[w1])); add2(ans, mul(mul(-fa[w3], fb[w1]), fc[w2])); add2(ans, mul(mul(-fa[w3], fb[w2]), fc[w1])); } // cout << ans << endl; } } } for(int i = 1; i <= num; i++) {//有兩個一樣 add2(ans, fuck(E[i].u, E[i].v, E[i].w)); add2(ans, fuck(E[i].v, E[i].u, E[i].w)); } for(int i = 1; i <= C; i++) {//全都一樣 if(mu[i] == 1) add2(ans, mul(mul(fa[i], fb[i]), fc[i])); else if(mu[i] == -1) add2(ans, -mul(mul(fa[i], fb[i]), fc[i]) + mod); } return ans; } void solve() { init(); A = read(); B = read(); C = read(); if(A < B) swap(A, B); if(C > B) swap(B, C); if(A < B) swap(A, B); Get(fa, A, A); Get(fb, A, B); Get(fc, A, C); Build(); cout << calc() << '\n'; } signed main() { // freopen("gg1.txt", "w", stdout); GetPrime(2e5); for(int T = read(); T; T--, solve()); return 0; }
loj#2565. 「SDOI2018」舊試題(反演 三元環計數)