• BZOJ 2301 Problem b


    Description

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

    Input

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

    Output

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

    Sample Input

    2
    2 5 1 5 1
    1 5 1 5 2

    Sample Output

    14
    3

    HINT

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

    板子题。
    首先我们学会求$$sum_{i=1}^{N} sum_{j=1}^{M}[gcd(i,j) = k]$$
    那么题目所求就可以用容斥原理来解决了。
    这个式子可以化为$$sum_{i=1}^{N} sum_{j=1}^{M}[gcd(lfloor frac{i}{k} floor,lfloor frac{j}{k} floor) = 1] = sum_{i=1}^{lfloor frac{N}{k} floor} sum_{j=1}^{lfloor frac{M}{k} floor}[gcd(i,j)=1]$$
    利用莫比乌斯反演$$sum_{i mid N} mu(i) = [N = 1]$$
    那么式子就可以化简为$$sum_{i=1}^{lfloor frac{N}{k} floor}sum_{j=1}^{lfloor frac{M}{k} floor}sum_{t mid i land t mid j} mu(t)$$
    先枚举(t),就可以得到$$sum_{t=1}^{min(lfloor frac{N}{k} floor,lfloor frac{M}{k} floor)}mu(t)lfloor frac{lfloor frac{N}{k} floor}{t} floor lfloor frac{lfloor frac{M}{k} floor}{t} floor$$
    然后就可以计算(mu)的前缀和,进行(sqrt{N})分段了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    #define maxn 100010
    int mu[maxn],prime[maxn],tot; bool exist[maxn];
    
    inline void ready()
    {
    	mu[1] = 1;
    	for (int i = 2;i <= 50000;++i)
    	{
    		if (!exist[i]) prime[++tot] = i,mu[i] = -1;
    		for (int j = 1;j <= tot&&i*prime[j] <= 50000;++j)
    		{
    			exist[i*prime[j]] = true;
    			if (i % prime[j] == 0) { mu[i*prime[j]] = 0; break; }
    			mu[i*prime[j]] = -mu[i];
    		}
    	}
    	for (int i = 1;i <= 50000;++i) mu[i] += mu[i-1];
    }
    
    inline int work(int a,int b,int k)
    {
    	a /= k; b /= k;
    	if (a > b) swap(a,b);
    	int ret = 0,pos;
    	for (int i = 1;i <= a;i = pos+1)
    	{
    		pos = min(a/(a/i),b/(b/i));
    		ret += (mu[pos]-mu[i-1])*(a/i)*(b/i);
    	}
    	return ret;
    }
    
    int main()
    {
    	freopen("2301.in","r",stdin);
    	freopen("2301.out","w",stdout);
    	ready();
    	int T; scanf("%d",&T);
    	while (T--)
    	{
    		int a,b,c,d,k,ans;
    		scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
    		ans = work(a-1,c-1,k)+work(b,d,k)-work(a-1,d,k)-work(b,c-1,k);
    		printf("%d
    ",ans);
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    检测mysq组复制的脚本
    centos7安装NFS
    mysql组复制安装
    springboot+VUE(一)
    redis集群配置
    codevs 3139 栈练习3
    codevs 3138 栈练习2
    codevs 2622 数字序列
    codevs 1054 电梯
    codevs 1507 酒厂选址
  • 原文地址:https://www.cnblogs.com/mmlz/p/4631174.html
Copyright © 2020-2023  润新知