LibreOJ 2565 「SDOI2018」旧试题

拿这个代码交了 JZOJ 4991(此题的 A,B,C5000 弱化版),成功拿到 14ms 最优解(

i=1Aj=1Bk=1Cd(ijk)=i=1Aj=1Bk=1Cx|iy|jz|k[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]=x=1Ay=1Bz=1CAxByCz[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]=x=1Ay=1Bz=1CAxByCzi|gcd(x,y)μ(i)j|gcd(x,z)μ(j)k|gcd(y,z)μ(k)=i=1min(A,B)μ(i)j=1min(A,C)μ(j)k=1min(B,C)μ(k)lcm(i,j)|xAxlcm(i,k)|yBylcm(j,k)|zCz

f0(n)=n|xAx,类似地有 f1,f2,上式变为

i=1min(A,B)μ(i)j=1min(A,C)μ(j)k=1min(B,C)μ(k)f0(lcm(i,j))f1(lcm(i,k))f2(lcm(j,k))

注意到可以把枚举的三元组 (i,j,k) 看做一堆三元环然后做三元环计数,同时统计答案。
注意到有很多无贡献的边可以直接删掉,包括 μ(u)=0,μ(v)=0,lcm(u,v)>min(A,B,C)u,v 的边。
于是我们剪枝剪掉一堆边之后边就变得很少了,直接暴力上三元环计数。

同时注意三元环计数无法考虑自环,特判一下有两个数相等或是三个数均相等的三元组即可。
据说 Cache Miss 使得 vector 存图会快很多?
参考了 GKxx 大佬的代码。

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
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5;
const long long mod = 1e9 + 7;
int T,A,B,C,mx,mn;
int vis[N + 5],cnt,prime[N + 5],mu[N + 5];
long long f[3][N + 5],ans;
int deg[N + 5];
vector<int> e[N + 5];
vector<long long> v[N + 5];
struct Edge
{
int u,v,w;
} g[(N << 4) + 5];
int tot;
int main()
{
mu[1] = 1;
for(register int i = 2;i <= N;++i)
{
if(!vis[i])
mu[prime[++cnt] = i] = -1;
for(register int j = 1;j <= cnt && i * prime[j] <= N;++j)
{
vis[i * prime[j]] = 1;
if(!(i % prime[j]))
break;
else
mu[i * prime[j]] = -mu[i];
}
}
memset(vis,0,sizeof vis);
scanf("%d",&T);
for(;T;--T)
{
scanf("%d%d%d",&A,&B,&C),mx = max(A,max(B,C)),mn = min(A,min(B,C)),ans = 0,memset(f,0,sizeof f);
for(register int i = 1;i <= A;++i)
for(register int j = i;j <= A;j += i)
f[0][i] += A / j;
for(register int i = 1;i <= B;++i)
for(register int j = i;j <= B;j += i)
f[1][i] += B / j;
for(register int i = 1;i <= C;++i)
for(register int j = i;j <= C;j += i)
f[2][i] += C / j;
for(register int i = 1;i <= mn;++i)
mu[i] && (ans += mu[i] * mu[i] * mu[i] * f[0][i] * f[1][i] * f[2][i]);
memset(deg,0,sizeof deg),tot = 0;
for(register int d = 1;d <= mx;++d)
for(register int i = 1;i * d <= mx;++i)
if(mu[i * d])
for(register int j = i + 1,x,y,lcm;(long long)i * j * d <= mx;++j)
if(mu[j * d] && __gcd(i,j) == 1)
x = i * d,y = j * d,lcm = i * j * d,
ans += mu[x] * mu[x] * mu[y] * (
f[0][x] * f[1][lcm] * f[2][lcm] +
f[0][lcm] * f[1][x] * f[2][lcm] +
f[0][lcm] * f[1][lcm] * f[2][x]),
ans += mu[x] * mu[y] * mu[y] * (
f[0][y] * f[1][lcm] * f[2][lcm] +
f[0][lcm] * f[1][y] * f[2][lcm] +
f[0][lcm] * f[1][lcm] * f[2][y]),
++deg[x],++deg[y],g[++tot] = (Edge){x,y,lcm};
for(register int i = 1;i <= mx;++i)
e[i].clear(),v[i].clear();
for(register int i = 1;i <= tot;++i)
if(deg[g[i].u] > deg[g[i].v] || (deg[g[i].u] == deg[g[i].v] && g[i].u < g[i].v))
e[g[i].u].push_back(g[i].v),v[g[i].u].push_back(g[i].w);
else
e[g[i].v].push_back(g[i].u),v[g[i].v].push_back(g[i].w);
for(register int x = 1;x <= mx;++x)
if(mu[x])
{
for(register int i = 0;i < e[x].size();++i)
vis[e[x][i]] = v[x][i];
for(register int i = 0,y,xy;i < e[x].size() && (y = e[x][i],xy = v[x][i],1);++i)
if(mu[y])
for(register int j = 0,z,xz,yz;j < e[y].size() && (z = e[y][j],xz = vis[z],yz = v[y][j],1);++j)
if(xz && mu[z])
ans += mu[x] * mu[y] * mu[z] * (
f[0][xy] * f[1][xz] * f[2][yz] +
f[0][xy] * f[1][yz] * f[2][xz] +
f[0][xz] * f[1][xy] * f[2][yz] +
f[0][xz] * f[1][yz] * f[2][xy] +
f[0][yz] * f[1][xy] * f[2][xz] +
f[0][yz] * f[1][xz] * f[2][xy]
);
for(register int i = 0;i < e[x].size();++i)
vis[e[x][i]] = 0;
}
printf("%lld\n",ans % mod);
}
}

Related Issues not found

Please contact @Alpha1022 to initialize the comment