zoukankan      html  css  js  c++  java
  • bzoj1101: [POI2007]Zap(莫比乌斯反演)

    原题链接

    题目描述:FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

    输入格式:第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。(1<=<=a,b<=50000)

    输出格式:对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。

    输入样例
    2
    4 5 2
    6 4

    输出样例
    3
    2
    //对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(6,3),(3,3)。

    解析:挺裸的莫比乌斯反演题。
       设(f(x)=gcd为x的(x,y)的对数)
       设(F(x)=gcd为x或x的倍数的(x,y)的对数)
       那么显然(F(x)=sum_{x|d}f(d))
       所以(f(x)=sum_{x|d}μ(⌊frac{d}{x}⌋)F(d))
       而(F(x)=⌊frac{n}{x}⌋⌊frac{m}{x}⌋)
       可得(f(x)=sum_{x|d}μ(⌊frac{d}{x}⌋)⌊frac{n}{d}⌋⌊frac{m}{d}⌋)
       枚举(⌊frac{d}{x}⌋),则(f(x)=sum_{i=1}^{min(⌊frac{n}{x}⌋,⌊frac{m}{x}⌋)}μ(i)⌊frac{n}{ix}⌋⌊frac{m}{ix}⌋)
       这时就可以用整除分块计算了

    代码如下:

    #include<cstdio>
    #include<algorithm>
    #define ll long long
    using namespace std;
    
    const int maxn = 5e4 + 5;
    int n, mu[maxn], primi[maxn], tot, mark[maxn], k, prim[maxn];
    ll sum[maxn], ans;
    
    int read(void) {
    	char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0';
    	while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x;
    }
    
    void get_mu(void) { //筛mu函数 
    	mu[1] = 1; mark[1] = 1;
    	int lim = maxn - 5;
    	  for (int i = 2; i <= lim; ++ i) {
    	  	if (!mark[i]) mu[i] = -1, prim[++ tot] = i;
    	  	for (int j = 1; j <= tot && prim[j] * i <= lim; ++ j) {
    	  		mark[prim[j] * i] = 1;
    	  		if (i % prim[j] == 0) break;
    	  		  else mu[prim[j] * i] = -mu[i];
    		  }
    	  }	
    	  for (int i = 1; i <= lim; ++ i) sum[i] = sum[i - 1] + mu[i]; //维护mu函数的前缀和 
    }
    
    int main() {
    	get_mu();
    	n = read();
    	  while (n --) {
    	  	int a = read(), b = read(), d = read();
    	  	a /= d; b /= d; ans = 0;
    	  	int lim = min(a, b); //整数分块计算 
    	  	  for (int l = 1, r; l <= lim; l = r + 1) {
    	  		  r = min(a / (a / l), b / (b / l));
    	  		  ans += (sum[r] - sum[l - 1]) * (a / l) *(b / l);
    	        }
    	    printf("%lld
    ", ans);
    	  }
    	return 0;
    } 
    
  • 相关阅读:
    MySQL核心知识学习之路()
    软件设计之路(5)
    软件设计之路(4)
    软件设计之路(4)
    软件设计之路(3)
    软件设计之路(2)
    软件设计之美-软件设计之路
    js将 “2021-07-06T06:23:57.000+00:00” 转换为年月日时分秒
    git pull/push 拉取/推送指定分支的代码
    git clone 指定分支的代码
  • 原文地址:https://www.cnblogs.com/Gaxc/p/10088151.html
Copyright © 2011-2022 走看看