欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

P4619 [SDOI2018]旧试题

发布时间:2023/12/3 43 豆豆
生活随笔 收集整理的这篇文章主要介绍了 P4619 [SDOI2018]旧试题 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

P4619 [SDOI2018]旧试题

题意:

求个式子:
(∑i=1A∑j=1B∑k=1Cd(i∗j∗k))mod(109+7)(\sum_{i=1}^{A}\sum_{j=1}^{B}\sum_{k=1}^{C}d(i*j*k))mod(10^9+7)(i=1Aj=1Bk=1Cd(ijk))mod(109+7)

题解:

原创博文1k纪念


很明显,莫比乌斯反演
马上更新




三元环链接
此等好题,作为第1000题的纪念

代码:

这个题让我写,我是真写不出来,非常适合练练莫比乌斯推导
代码条例非常清晰,很适合阅读

#include <bits/stdc++.h> #define ll long long using namespace std; const int N= 1e5 + 7; const int M= 1e6 + 7; const int mod= 1e9 + 7; bool Prime[N]; int tot, P[N >> 3], mu[N]; void get_mu() {mu[1]= 1;for (int i= 2; i <= 1e5; i++) {if (!Prime[i])P[++tot]= i, mu[i]= -1;for (int j= 1; P[j] * i <= 1e5 && j <= tot; j++) {Prime[P[j] * i]= 1;if (i % P[j] == 0) {mu[P[j] * i]= 0;break;}mu[P[j] * i]= -mu[i];}} } vector<int> ve[N]; unordered_map<int, bool> mp[N]; int T, Max, A, B, C, ans, p[N]; int sA[M], sB[M], sC[M], cnt, deg[N]; int gcd(int x, int y) {return x == 0 ? y : gcd(y % x, x); } ll lcm(int x, int y) {return 1ll * x / gcd(x, y) * y; } int ta, tb, tc, sum; void cal(int a, int b, int c)//求后半程三个累加的答案 {sum=(sum+ 1ll * p[a / ta] * p[b / tb] % mod * p[c / tc] % mod)% mod; } void get(int a, int b, int c) {sum= 0;if (a == b && b == c)cal(A, B, C);else if (a == b || b == c || c == a) {cal(A, B, C);cal(C, A, B);cal(B, C, A);}else {//三个点的值都不一样,完全排列 cal(A, B, C);cal(A, C, B);cal(B, A, C);cal(B, C, A);cal(C, A, B);cal(C, B, A);}//记录后半程的答案 ans= (ans + (mu[a] * mu[b] * mu[c] * sum % mod + mod) % mod) % mod;//记录前半程答案 } int vis[N]; void solve() {for (int i= 1; i <= cnt; i++) { int &u= sA[i], &v= sB[i];if (deg[u] < deg[v])swap(u, v);else if (deg[u] == deg[v] && u > v)swap(u, v);ve[u].push_back(i);//存的点的编号,为了方便后面取值 }for (int i= 1; i <= Max; i++) {//跑三元环 for (int j : ve[i])vis[sB[j]]= sC[j];for (int j : ve[i])for (int k : ve[sB[j]])if (vis[sB[k]]) {ta= vis[sB[k]];//分别是三个lcm tb= sC[j];tc= sC[k];get(i, sB[j], sB[k]);//三个点的值 }for (int j : ve[i])vis[sB[j]]= 0;} } void getans(int x) {for (int l= 1, r; l <= x; l= r + 1) {r= (x / (x / l));p[x]= (p[x] + 1ll * (r - l + 1) * (x / l) % mod) % mod;//整除分块前缀和 } } int main() {scanf("%d", &T);get_mu();for (int i= 1; i <= 1e5; i++)getans(i);while (T--) {scanf("%d%d%d", &A, &B, &C);ans= cnt= 0;Max= max(max(A, B), C);for (int i= Max; i >= 1; i--) {//i枚举的是三数的人最大公约数for (int j= i; j <= Max; j+= i) {if (!mu[j])continue;for (int k= j; 1ll*k*j /i<= 1ll * Max; k+= i) {//k*j/i就是这个两个数的lcm,要小于等于Max if (!mu[k])continue;if (!mp[j][k]) { // printf("%d %d %d i=%d\n", j, k, j / i * k,i);++cnt;sA[cnt]= j;sB[cnt]= k;sC[cnt]= 1ll*j*k/ i ;//sC是j和k的最小公倍数 deg[j]++;deg[k]++;mp[j][k]= 1;}}}}solve();for (int i= 1; i <= Max; i++) {ve[i].clear();mp[i].clear();deg[i]= 0;}printf("%d\n", (ans + mod) % mod);}return 0; }

总结

以上是生活随笔为你收集整理的P4619 [SDOI2018]旧试题的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。