• luogu2257 YY的GCD--莫比乌斯反演


    link

    给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对

    多组数据T = 10000

    N, M <= 10000000

    推式子

    (sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=p])

    (=sum_psum_{i=1}^{n/p}sum_{j=1}^{m/p}[gcd(i,j)=1])

    (=sum_psum_{i=1}^{n/p}sum_{j=1}^{m/p}sum_{d|i,d|j}mu(d))

    (=sum_{d=1}^nmu(d)sum_plfloorfrac n{dp} floorlfloorfrac m{dp} floor)

    (q=dp)

    (=sum_{q=1}^n(sum_{p|q}mu(frac q p))lfloorfrac nq floorlfloorfrac mq floor)

    (mu)线性筛

    然后在对于质数枚举倍数求对于每个(i)(sum_{p|i}mu(frac i p))

    然后打数论分块就行了

    #include <cstdio>
    #include <functional>
    using namespace std;
    
    const int fuck = 10000000;
    int prime[10000010], tot;
    bool vis[10000010];
    int mu[10000010], sum[10000010];
    
    int main()
    {
    	mu[1] = 1;
    	for (int i = 2; i <= fuck; i++)
    	{
    		if (vis[i] == false) prime[++tot] = i, mu[i] = -1;
    		for (int j = 1; j <= tot && i * prime[j] <= fuck; j++)
    		{
    			vis[i * prime[j]] = true;
    			if (i % prime[j] == 0) break;
    			mu[i * prime[j]] = -mu[i];
    		}
    	}
    	for (int i = 1; i <= tot; i++)
    		for (int j = 1; j * prime[i] <= fuck; j++)
    			sum[j * prime[i]] += mu[j];
    	for (int i = 1; i <= fuck; i++)
    		sum[i] += sum[i - 1];
    	int t; scanf("%d", &t);
    	while (t --> 0)
    	{
    		int n, m;
    		long long ans = 0; //别忘了初始化。。。
    		scanf("%d%d", &n, &m);
    		if (n > m) {int t = m; m = n; n = t; }
    		for (int i = 1, j; i <= n; i = j + 1)
    		{
    			j = min(n / (n / i), m / (m / i));
    			ans += (sum[j] - sum[i - 1]) * (long long)(n / i) * (m / i);
    		}
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    视频像素点级的标注
    unet
    Emmet缩写语法
    Nginx漏洞利用与安全加固
    算法时间复杂度
    动态规划dp
    数据结构Java实现04---树及其相关操作
    关于递归
    Java正则表达式
    Java String相关
  • 原文地址:https://www.cnblogs.com/oier/p/10295755.html
Copyright © 2020-2023  润新知