2019 年百度之星·程序设计大赛 - 初赛三 1003

题意:
求\(\sum_{i=1}^n\sum_{j=1}^m \mu({lcm(i,j)})\)。

思路:
首先\(lcm(i,j)=\frac{ij}{gcd(i,j)}\),不妨有\(lcm(i,j)\)无平方因子,那么就有\(gcd(\frac{i}{gcd(i,j)},j)\)互质,所以\(\mu(lcm(i,j))=\mu(i)\mu(j)\mu(gcd(i,j))\);如果\(lcm(i,j)\)有平方因子的话,不影响答案。
注意\(mu\)的值和质因子个数有关,所以我们可以直接将"除以"写成"乘"。
下面就是推式子时间:

\[
\begin{aligned}
&\sum_{i=1}^n \sum_{j=1}^m \mu(lcm(i,j))\=&\sum_{i=1}^n \sum_{j=1}^m \mu(i) \mu(j) \mu(gcd(i,j))\=&\sum_d\sum_i\sum_j\mu(i)\mu(j)\mu(d)\ (gcd(i,j)=d)\=&\sum_d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \mu(id)\mu(jd)\mu(d)\ (gcd(i,j)=1)\=&\sum_d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \mu(id)\mu(jd)\mu(d)\sum_{k|gcd(i,j)}\mu(k)\=&\sum_{d=1}^{min(n,m)}\sum_k\mu(k)\sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor}\mu(ikd)\mu(jkd)\mu(d)
\end{aligned}
\]
令\(T=kd,T\leq min(n,m)\),则上式为:
\[
\sum_T\sum_{d|T}\mu(\frac{T}{d})\mu(d)\sum_{i=1}^{\lfloor\frac{n}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{T}\rfloor}\mu(iT)\mu(jT)
\]
之后对于每个\(T\),预处理\(\sum_d\mu(\frac{T}{d})\mu(d)\)即可,时间复杂度\(O(nlogn)\)。
后部分可以直接暴力,总时间复杂度为\(O(Tnlogn)\)。

#include <bits/stdc++.h>
#define heyuhhh ok
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int T;
int mu[N], p[N];
ll sum[N];
bool chk[N];
void init() {
    mu[1] = 1;
    int cnt = 0, k = N - 1;
    for(int i = 2; i <= k; i++) {
        if(!chk[i]) p[++cnt] = i, mu[i] = -1;
        for(int j = 1; j <= cnt && i * p[j] <= k; j++) {
            chk[i * p[j]] = 1;
            if(i % p[j] == 0) {mu[i * p[j]] = 0; break;}
            mu[i * p[j]] = -mu[i];
        }
    }
    for(int i = 1; i <= k; i++) {
        for(int j = i; j <= k; j += i) {
            sum[j] += mu[i] * mu[j / i];
        }
    }
}
int n, m;
int main() {
#ifdef heyuhhh
    freopen("input.in", "r", stdin);
#else
    ios::sync_with_stdio(false); cin.tie(0);
#endif
    init();
    cin >> T;
    while(T--) {
        cin >> n >> m;
        ll ans = 0;
        for(int t = 1; t <= min(n, m); ++t) {
            ll s1 = 0, s2 = 0;
            for(int i = 1; i <= m / t; ++i) s1 += mu[i * t];
            for(int i = 1; i <= n / t; ++i) s2 += mu[i * t];
            ans += sum[t] * s1 * s2;
        }
        cout << ans << '\n';
    }
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/11408744.html

时间: 2024-11-13 11:00:19

2019 年百度之星·程序设计大赛 - 初赛三 1003的相关文章

2019 年百度之星&#183;程序设计大赛 - 初赛三

P.S:关于初赛二,在高铁上打代码真是奇怪的体验!!! 1003,1004的题解很不错,学习了! =========================================== 一开场把所有的题目看了一遍,这题面风格,感觉凉凉.还好,往下做时,题目不是太坑. 1002 floyd转dijkstra+堆优化,感觉是套路题了 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include

2019年百度之星&#183;程序设计大赛 初赛一 题解

1001 Polynomial:若第一个多项式的次数大于第二个,就是1/0,若小于就是0/1,若等于就是第一个多项式最高次项系数/第二个多项式最高次项系数. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 typedef long long ll; 6 using namespace st

2019 年百度之星&#183;程序设计大赛 - 初赛二

1001 度度熊与数字 #pragma comment(linker, "/STACK:36777216") #include <bits/stdc++.h> #define REP(i,n) for(int i=0;i<int(n);++i) #define FOR(i,a,b) for(int i=int(a);i<int(b);++i) #define DWN(i,b,a) for(int i=int(b);i>=int(a);--i) /// ty

2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)

题目链接 分析:打表以后就能发现时卡特兰数, 但是有除法取余. f[i] = f[i-1]*(4*i - 2)/(i+1); 看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展gcd, 不是用逆元吗.. 网上还有别人的解释,没看懂,贴一下: (a / b) % m = ( a % (m*b)) / b 笔者注:鉴于ACM题目特别喜欢M=1000000007,为质数: 当gcd(b,m) = 1, 有性质: (a/b)%m = (a*b^-1)%m, 其中b^-1是b模m的逆

2014年百度之星程序设计大赛 - 初赛(第二轮)

1001 暴力 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 100100; int ll[maxn], rr[maxn]; struct node { int x, y, bj; }e[maxn]; int main() { int cas = 1; int T; scanf("%d", &T);

2014年百度之星程序设计大赛 - 初赛(第二轮)Chess

题目描述:小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘上的走法遵循十字路线.也就是说,如果"王"当前在(x,y)点,小度在下一步可以移动到(x+1, y), (x-1, y), (x, y+1), (x, y-1), (x+2, y), (x-2, y), (x, y+2), (x, y-2) 这八个点中的任意一个. 小度觉得每次都是小良赢,没意思.为了难倒小良,他想出

2017&quot;百度之星&quot;程序设计大赛 - 初赛(A)

2017"百度之星"程序设计大赛 - 初赛(A) hdu6108    求出 n-1 的因子个数即可 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b;

HDU 6114 Chess 【组合数】(2017&quot;百度之星&quot;程序设计大赛 - 初赛(B))

Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 513    Accepted Submission(s): 319 Problem Description 車是中国象棋中的一种棋子,它能攻击同一行或同一列中没有其他棋子阻隔的棋子.一天,小度在棋盘上摆起了许多車--他想知道,在一共N×M个点的矩形棋盘中摆最多个数的車使其互不攻

HDU 6119 小小粉丝度度熊 【预处理+尺取法】(2017&quot;百度之星&quot;程序设计大赛 - 初赛(B))

小小粉丝度度熊 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1572    Accepted Submission(s): 513 Problem Description 度度熊喜欢着喵哈哈村的大明星--星星小姐. 为什么度度熊会喜欢星星小姐呢? 首先星星小姐笑起来非常动人,其次星星小姐唱歌也非常好听. 但这都不是最重要的,最重要的是