HAOI2011 Problem b

Problem b

link

做法:莫比乌斯反演。

思路:

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

f ⁡ ( n ) = ∑ i = 1 x ∑ j = 1 y [ n ∣ gcd ⁡ ( i , j ) ] \operatorname{f}(n)=\sum\limits_{i=1}^x \sum\limits_{j=1}^y [n|\gcd(i,j)] f(n)=i=1xj=1y[ngcd(i,j)]

a n s = g ⁡ ( n ) = ∑ i = 1 x ∑ j = 1 y [ gcd ⁡ ( x , y ) = k ] ans=\operatorname{g}(n)=\sum\limits_{i=1}^x \sum\limits_{j=1}^y [\gcd(x,y)=k] ans=g(n)=i=1xj=1y[gcd(x,y)=k]

利用容斥原理,答案为图像上蓝色部分:

HAOI2011 Problem b_第1张图片

问题在于如何求 g ⁡ ( x , y ) \operatorname{g}(x,y) g(x,y)

我们知道:

f ⁡ ( n ) = ∑ n ∣ d g ⁡ ( d ) \operatorname{f}(n)=\sum\limits_{n|d}\operatorname{g}(d) f(n)=ndg(d)

利用莫比乌斯反演可得:

g ⁡ ( n ) = ∑ n ∣ d μ ⁡ ( d n ) f ⁡ ( n ) \operatorname{g}(n)=\sum\limits_{n|d}\operatorname{\mu}(\frac{d}{n})\operatorname{f}(n) g(n)=ndμ(nd)f(n)

μ ⁡ ( d n ) \operatorname{\mu}(\frac{d}{n}) μ(nd) 可以利用线性筛求出, f ⁡ ( d ) \operatorname{f}(d) f(d) 易得 f ⁡ ( d ) = ⌊ x n ⌋ ⌊ y n ⌋ \operatorname{f}(d)=\left\lfloor\frac{x}{n}\right\rfloor \left\lfloor\frac{y}{n}\right\rfloor f(d)=nxny

答案可以推出:

a n s = ∑ n ∣ d μ ⁡ ( d n ) f ⁡ ( d ) = ∑ i = 1 min ⁡ ( x , y ) μ ⁡ ( i ) ⌊ x i ⋅ n ⌋ ⌊ y i ⋅ n ⌋ ans=\sum\limits_{n|d}\operatorname{\mu}(\frac{d}{n})\operatorname{f}(d)=\sum\limits_{i=1}^{\min(x,y)}\operatorname{\mu}(i)\left\lfloor\frac{x}{i\cdot n}\right\rfloor \left\lfloor\frac{y}{i\cdot n}\right\rfloor ans=ndμ(nd)f(d)=i=1min(x,y)μ(i)inxiny

再利用数论分块以及前缀和优化一下就不会超时了。

代码:

#include
#include
#include
#include
#include
typedef long long LL;
typedef unsigned long long ULL;
namespace FastIo{
    typedef __uint128_t ULLL;
    static char buf[100000],*p1=buf,*p2=buf,fw[100000],*pw=fw;
    #define gc p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++
    inline void pc(const char &ch){
    	if(pw-fw==100000)fwrite(fw,1,100000,stdout),pw=fw;
    	*pw++=ch;
	}
    #define fsh fwrite(fw,1,pw-fw,stdout),pw=fw
	struct FastMod{
        FastMod(ULL b):b(b),m(ULL((ULLL(1)<<64)/b)){}
        ULL reduce(ULL a){
            ULL q=(ULL)((ULLL(m)*a)>>64);
            ULL r=a-q*b;
            return r>=b?r-b:r;
        }
        ULL b,m;
    }HPOP(10);
    struct QIO{
    	char ch;
    	int st[40];
    	template<class T>inline void read(T &x){
    		x=0,ch=gc;
    		while(!isdigit(ch))ch=gc;
    		while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
		}
		template<class T>inline void write(T a){
			do{st[++st[0]]=HPOP.reduce(a);a/=10;}while(a);
			while(st[0])pc(st[st[0]--]^48);
			pc('\n');
		}
	}qrw;
}
using namespace FastIo;
#define P(A) A=-~A
#define fione(i,a,b) for(register int i=a;i<=b;P(i))
const int NUMBER1=5e4;
int prime[NUMBER1+5],cnt(0);
LL mu[NUMBER1+5];
bool pd[NUMBER1+5];
inline void PRIME(){
	int k;
	mu[1]=1;
	fione(i,2,NUMBER1){
		if(!pd[i])prime[++cnt]=i,mu[i]=-1;
		for(register int j(1);prime[j]*i<=NUMBER1;P(j)){
			k=prime[j]*i;
			pd[k]=true;	
			if(!(i%prime[j]))break;
			mu[k]-=mu[i];
		}
	}
	fione(i,1,NUMBER1)mu[i]+=mu[i-1];
}
inline int fk(int k,int x){return k/(k/x);}
inline LL work(int x,int y,int k){
	x/=k,y/=k;
	LL ans(0);int n=std::min(x,y);
	for(register int l=1,r;l<=n;l=r+1){
		r=std::min(n,std::min(fk(x,l),fk(y,l)));
		ans+=(mu[r]-mu[l-1])*(x/l)*(y/l);
	}
	return ans;
}
signed main(){
	PRIME();
	int T,a,b,c,d,k;
	qrw.read(T);
	while(T--){
		qrw.read(a);
		qrw.read(b);
		qrw.read(c);
		qrw.read(d);
		qrw.read(k);
		qrw.write(work(b,d,k)-work(a-1,d,k)-work(b,c-1,k)+work(a-1,c-1,k));
	}
	fsh;
    exit(0);
    return 0;
}

你可能感兴趣的:(算法,c++)