• P2522 [HAOI2011]Problem b


    (color{#0066ff}{ 题目描述 })

    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

    (color{#0066ff}{输入格式})

    第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

    (color{#0066ff}{输出格式})

    共n行,每行一个整数表示满足要求的数对(x,y)的个数

    (color{#0066ff}{输入样例})

    2
    2 5 1 5 1
    1 5 1 5 2
    

    (color{#0066ff}{输出样例})

    14
    3
    

    (color{#0066ff}{数据范围与提示})

    100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

    (color{#0066ff}{ 题解 })

    abcd的范围有些恶心,考虑拆开算

    显然可以当做二维前缀和一样的东西处理

    因此转化为求

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

    把k除过去

    [sum_{i=1}^{lfloor frac n k floor} sum_{j=1}^{lfloor frac m k floor} [gcd(i,j)==1] ]

    因为有

    [e(n)=[n==1] ]

    [mu*i=e ]

    [i(n)=1 ]

    所以

    [e(n)=sum_{d|n} mu(d)*i(frac n d)=sum_{d|n} mu(d) ]

    因此原式可以化成

    [sum_{i=1}^{lfloor frac n k floor} sum_{j=1}^{lfloor frac m k floor} sum_{d|gcd(i,j)} mu(d) ]

    [d|gcd(i,j) o d|i ,d|j ]

    i和j都是d的倍数,考虑枚举d,那么有多少i,j满足是d的倍数呢?

    原式变成

    [sum_{d=1}^{min(lfloor frac n k floor,lfloor frac m k floor)} mu(d) *lfloor frac{n}{kd} floor * lfloor frac{m}{kd} floor ]

    (mu)前缀和一下,然后后面整数分块搞一搞就行了

    还有懵逼鸟斯推法这是什么??

    来自--y2823774827y

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 1e5 + 10;
    int k;
    int pri[maxn], mu[maxn], tot;
    bool vis[maxn];
    void predoit() {
    	mu[1] = 1;
    	for(int i = 2; i <= 50505; i++) {
    		if(!vis[i]) pri[++tot] = i, mu[i] = -1;
    		for(int j = 1; j <= tot && i * pri[j] <= 50505; j++) {
    			vis[i * pri[j]] = true;
    			if(i % pri[j] == 0) break;
    			else mu[i * pri[j]] = -mu[i];
    		}
    	}
    	for(int i = 2; i <= 50505; i++) mu[i] += mu[i - 1];
    }
    LL work(int n, int m) {
    	n /= k, m /= k;
    	LL ans = 0;
    	for(int l = 1, r; l <= std::min(n, m); l = r + 1) {
    		r = std::min(n / (n / l), m / (m / l));
    		ans += (LL)(n / l) * (m / l) * (mu[r] - mu[l - 1]);
    	}
    	return ans;
    }
    int main() {
    	predoit();
    	for(int T = in(); T --> 0;) {
    		int a = in(), b = in(), c = in(), d = in();
    		k = in();
    		printf("%lld
    ", work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    C#生成MD5的方法
    平常心是道
    Android 三种动画的使用 – Tween Animation
    17个Javascript日期选择器
    Javascript解码编码常用函数
    mysql 命令行导入导出数据
    技术驱动还是产品驱动
    Ubuntu 和 Redhat / Fedora 服务管理命令对比表
    jquery常用技巧
    Fedora 17安装JDK1.7
  • 原文地址:https://www.cnblogs.com/olinr/p/10293961.html
Copyright © 2020-2023  润新知