uoj426
题意
给 \(n,\ N,\ m,\ x_1,\ x_2,\ ...,\ x_m,\ y_1,\ y_2,\ ...,\ y_m\)。
问 \(\sum_{a_1=1}^N\sum_{a_2=1}^N\dots\sum_{a_n=1}^N\ \sigma_0(gcd(a_1,\ a_2,\ ...,\ a_n)^3)^3\ \Pi_{i=1}^m[a_{x_i}\leq a_{y_i}]\bmod 2^{32}\),其中 \(\sigma_0(n)\) 表示 \(n\) 的约数个数。
\(1\ \leq\ n\ \leq\ 20,\ 1\ \leq\ N\ \leq\ 10^{10},\ 1\ \leq\ m\ \leq\ n(n\ -\ 1)\)。
做法1
令 \(ways(x)\ =\ \sum_{a_1=1}^x\sum_{a_2=1}^x\dots\sum_{a_n=1}^x\ \ \Pi_{i=1}^m[a_{x_i}\leq a_{y_i}]\bmod 2^{32}\)。则 \(ans\ =\ \sum_{d=1}^N\ \sigma_0(d^3)^3\sum_{e=1}^{\left\lfloor\frac{N}{d}\right\rfloor}\mu(e)\cdot ways(\left\lfloor\frac{N}{de}\right\rfloor)\ \\=\ \sum_{x=1}^N\ ways(\left\lfloor\frac{N}{x}\right\rfloor)\sum_{d|x}\ \sigma_0(d^3)^3\mu(\frac{x}{d})\)。
令 \(F(n)\ =\ \sum_{d|n}\ \sigma_0(d^3)^3\mu(\frac{x}{d})\)。枚举 \(\left\lfloor\frac{N}{x}\right\rfloor\) 计算后面的式子即可。问题转化成求 \(ways(x)\) 和 \(F(x)\) 的前缀和。
考虑用 \(min\_25\) 筛来求 \(F(x)\) 的前缀和。令 \(S(p,\ n)\ =\ \sum_{i=1}^n[i\) 的质因子都 \(\geq p] F(i)\),用滚动数组存下 \(S_p(n)\) 即可。
求 \(ways(x)\) 可以先求出 \(a\) 有 \(k\) 个不同的值的方案数。求 \(a\) 有 \(k\) 个不同值得方案数考虑状压 \(dp\),令 \(f(k,\ u,\ S)\) 表示 \(a_v\ \leq\ k\ +\ [v\leq u],\ v\in S\) 的方案数。
时间复杂度 \(O(\frac{N^{\frac{3}{4}}}{logN}\ +\ n^22^n\ +\ n\sqrt{N})\)。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
using u32 = unsigned int;
namespace graph {
int n, m, N;
vector<u32> res, pw2(32);
void init() {
pw2[0] = 1;
for (int i = 1; i < 32; ++i) pw2[i] = pw2[i - 1] << 1;
vector<vector<int> > g(n), rg(n);
while(m--) {
int u, v;
cin >> u >> v;
g[u - 1].push_back(v - 1);
rg[v - 1].push_back(u - 1);
}
vector<bool> vis(n, false);
vector<int> col(n, -1), ord;
function<void(int)> dfs_ord = [&](int u) {
vis[u] = 1;
for (int v: g[u]) if(!vis[v]) dfs_ord(v);
ord.push_back(u);
return;
};
for (int u = 0; u < n; ++u) if(!vis[u]) dfs_ord(u);
reverse(ord.begin(), ord.end());
function<void(int)> dfs_col = [&](int u) {
col[u] = N;
for (int v: rg[u]) if(!~col[v]) dfs_col(v);
return;
};
for (int u: ord) if(!~col[u]) dfs_col(u), ++N;
vector<int> G(N, 0);
for (int u = 0; u < n; ++u) for (int v: g[u]) if(col[u] != col[v]) G[col[v]] |= (1 << col[u]);
int S = 1 << N;
vector<u32> dp(S, 0), pd(S);
dp[0] = 1;
res = vector<u32>(N + 1, 0);
for (int i = 1; i <= N; ++i) {
auto foo = dp;
for (int u = 0; u < N; ++u) {
fill(pd.begin(), pd.end(), 0);
u32 t;
for (int s = 0; s < S; ++s) if(t = dp[s]) {
pd[s] = pd[s] + t;
if((!((s >> u) & 1)) && ((s & G[u]) == G[u])) pd[s | (1 << u)] = pd[s | (1 << u)] + t;
}
dp = pd;
}
for (int s = 0; s < S; ++s) dp[s] -= foo[s];
res[i] = dp[S - 1];
}
return;
}
u32 Q(long long n) {
u32 ret = 0, x = 1, y = 0;
for (int i = 1; i <= N; ++i) {
auto work = [&](long long n) {
u32 y = 0;
while(~n & 1) n >>= 1, ++y;
return make_pair((u32)n, y);
};
auto inv = [&](u32 ua) {
long long a = ua, b = 1ll << 32, x, y;
function<void(long long, long long &, long long, long long &)> extgcd = [&](long long a, long long &x, long long b, long long &y) {
if(!b) { x = 1; y = 0; return; }
long long c = a / b;
extgcd(b, y, a - c * b, x);
y -= x * c;
return;
};
extgcd(a, x, b, y);
return (u32)x;
};
if(i > n) break;
auto t = work(n - i + 1);
x *= t.first; y += t.second;
t = work(i);
x *= inv(t.first); y -= t.second;
ret += x * (y >= 32 ? 0 : pw2[y]) * res[i];
}
return ret;
}
}
namespace func {
long long N, B;
vector<u32> s1, s2;
constexpr u32 pool[] = {0, 1, 64, 127, 406, 469};
void init() {
B = floor(sqrt(1. * N)) + 10;
while(B * B > N) --B;
vector<bool> isp(B + 1, true);
vector<int> pme;
for (int x = 2; x <= B; ++x) {
if(isp[x]) pme.push_back(x);
for (int p: pme) {
int y = p * x;
if(y > B) break;
isp[y] = 0;
if(x % p == 0) break;
}
}
vector<u32> cnt1(B + 1, 0), cnt2(N / (B + 1) + 1, 0);
for (int x = 1; x <= B; ++x) cnt1[x] = x - 1;
for (int x = 1; x < cnt2.size(); ++x) cnt2[x] = u32(N / x - 1);
for (int p: pme) {
long long q = (long long) p * p;
u32 t = cnt1[p - 1];
for (int x = 1; x < cnt2.size(); ++x) {
long long n = N / x;
if(n < q) break;
n /= p;
if(n <= B) cnt2[x] -= cnt1[n] - t;
else cnt2[x] -= cnt2[x * p] - t;
}
for (int x = B; x >= q; --x) cnt1[x] -= cnt1[x / p] - t;
}
s1 = vector<u32>(cnt1.size(), 0);
s2 = vector<u32>(cnt2.size(), 0);
for (int _ = pme.size() - 1; ~_; --_) {
int p = pme[_];
long long q = (long long) p * p, qq = (_ == pme.size() - 1 ? N + 1 : (long long) pme[_ + 1] * pme[_ + 1]);
auto S = [&](long long n) {
if(n < qq) return n >= p ? ((n > B ? cnt2[N / n] : cnt1[n]) - cnt1[p]) * 63 : 0;
return n > B ? s2[N / n] : s1[n];
};
for (int x = 1; x < cnt2.size(); ++x) {
long long n = N / x;
if(n < q) break;
long long q = n / p, ret = S(n);
int k = 1;
while(q) {
ret += (1 + S(q)) * (81 * k * k - 27 * k + 9);
++k;
q /= p;
}
s2[x] = ret;
}
for (int n = B; n >= q; --n) {
long long q = n / p, ret = S(n);
int k = 1;
while(q) {
ret += (1 + S(q)) * (81 * k * k - 27 * k + 9);
++k;
q /= p;
}
s1[n] = ret;
}
}
return;
}
u32 Q(long long n) {
return n <= 5 ? pool[n] : (n > B ? s2[N / n] : s1[n]) + 1;
}
}
int main() {
cin >> graph::n >> func::N >> graph::m;
graph::init();
func::init();
u32 ans = 0;
for (long long x = 1; x <= func::N; ++x) {
long long y = func::N / (func::N / x);
ans += graph::Q(func::N / x) * (func::Q(y) - func::Q(x - 1));
x = y;
}
cout << ans << endl;
return 0;
}