• 【刷题】BZOJ 2301 [HAOI2011]Problem b


    Description

    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤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≤c≤d≤50000,1≤k≤50000

    Solution

    这一题也是莫比乌斯反演
    式子和上一篇的一模一样
    所以接下来的(solve)怎么求可以看上篇和上上篇,这里只列出一个式子

    [solve(n,m,k)=f(k)=sum_{T=1}^{min(n,m)}mu(lfloor frac{T}{k} floor)lfloor frac{n}{T} floor lfloor frac{m}{T} floor ]

    (mu)作线性筛和前缀和,枚举作整除分块

    这题因为有下界,所以我们需要容斥一下

    [ans=solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k) ]

    这里的(solve(n,m,k))就是求满足(1 le x le n)(1 le y le m)时,有多少数对((x,y))的gcd等于k
    感性上,就是 (||) 1到b和1到d的整段 (||) 先减去 (||) 1到a-1和1到d的整段 (||) ,这样就去除了1到a-1段中的贡献;同理,再减去1到c-1段中的贡献,这样多算的就去掉了,但发现
    (||) 1到a-1和1到c-1的整段 (||) 减了两次,所以又要加上来
    但这样做还是是会超时
    我们又发现(solve(n,m,k)=solve(n/k,m/k,1))
    因为在n/k和m/k中的gcd为1的数对同时乘以k,那么他们的gcd就变成了k,而且也不会超上界
    那么我们的ans就可以变为

    [ans=solve'(b/k,d/k)-solve'((a-1)/k,d/k)-solve'(b/k,(c-1)/k)+solve'((a-1)/k,(c-1)/k) ]

    ((solve'(n,m)=solve(n,m,1)))

    #include<bits/stdc++.h>
    #define ll long long
    const int MAXN=50000+1;
    int T,prime[MAXN],cnt,mu[MAXN],s[MAXN];
    bool vis[MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void init()
    {
    	memset(vis,1,sizeof(vis));
    	vis[0]=vis[1]=0;
    	mu[1]=1;
    	for(register int i=2;i<MAXN;++i)
    	{
    		if(vis[i])
    		{
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(register int j=1;j<=cnt&&i*prime[j]<MAXN;++j)
    		{
    			vis[i*prime[j]]=0;
    			if(i%prime[j])mu[i*prime[j]]=-mu[i];
    			else break;
    		}
    	}
    	for(register int i=1;i<MAXN;++i)s[i]=s[i-1]+mu[i];
    }
    inline ll solve(int a,int b)
    {
    	ll res=0;
    	for(register int i=1;;)
    	{
    		if(i>min(a,b))break;
    		int j=min(a/(a/i),b/(b/i));
    		res+=(ll)(a/i)*(ll)(b/i)*(ll)(s[j]-s[i-1]);
    		i=j+1;
    	}
    	return res;
    }
    int main()
    {
    	init();
    	read(T);
    	while(T--)
    	{
    		int a,b,c,d,k;
    		read(a);read(b);read(c);read(d);read(k);
    		write(solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k),'
    ');
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    memcached学习笔记——存储命令源码分析上篇
    个人理解正则表达式——懒惰匹配
    Symfony2中的设计模式——装饰者模式
    Symfony2源码分析——启动过程2
    Symfony2 HttpKernel事件驱动
    memcached学习笔记——连接模型
    阅读优秀代码是提高开发人员修为的一种捷径
    Linux下部署Symfony2对app/cache和app/logs目录的权限设置
    Symfony2源码分析——启动过程1
    Symfony2 EventDispatcher组件
  • 原文地址:https://www.cnblogs.com/hongyj/p/8535574.html
Copyright © 2020-2023  润新知