BZOJ1101——[POI2007]Zap

来源:互联网 发布:淘宝网针织衫开衫短款 编辑:程序博客网 时间:2024/06/07 01:03

1、题意:对于给定的整数a,bd,有多少正整数对(x,y),满足xayb,并且gcd(x,y)=d
2、分析:这种题就是要推倒式子嘛。那个gcd(x,y)=d,我们可以将ab都除以d,这样就是变成求互质的个数了。。假设已经除完
Ans=ai=1bj=1[gcd(i,j)=1]
μ函数的性质d|nμ(d)=[n=1]显然可以得到
Ans=ai=1bj=1d|gcd(i,j)μ(d)
那么我们可以枚举gcd(i,j),整理得
Ans=min(a,b)d=1μ(d)ndmd
后面的那个ndmd最多有2n个取值。
那么预处理μ的前缀和,即可在O(2n)的复杂度内完成单次询问。μ的值可以用筛法求出来。

#include <map>#include <set>#include <cmath>#include <queue>#include <vector>#include <bitset>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define M 100010#define LL long long#define MOD 1000000007#define inf 2147483647#define llinf 4000000000000000000ll#define For(i, x, y) for(int i = (x); i < (y); i ++)#define rep(i, x, y) for(int i = (x); i <= (y); i ++)#define drep(i, x, y) for(int i = (x); i >= (y); i --)inline int read(){    char ch=getchar();int x=0,f=1;    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}inline LL llread(){    char ch=getchar();LL x=0,f=1;    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int mu[M], prime[M], tot;bool vis[M];inline void init(){    mu[1] = 1;    For(i, 2, M){        if(!vis[i]){            mu[i] = -1;            prime[++ tot] = i;        }        rep(j, 1, tot){            if(i * prime[j] >= M) break;            vis[i * prime[j]] = 1;            if(i % prime[j] == 0){                mu[i * prime[j]] = 0;                break;            }            mu[i * prime[j]] = -mu[i];        }    }    For(i, 1, M) mu[i] += mu[i - 1];}inline int solve(int n, int m){    int ret = 0, la;    for(int i = 1; i <= n; i = la + 1){        la = min(n / (n / i), m / (m / i));        ret += (n / i) * (m / i) * (mu[la] - mu[i - 1]);    }    return ret;}int main(){    //freopen("0input.in", "r", stdin);    int T = read(); init();    while(T --){        int n = read(), m = read(), d = read();        n /= d; m /= d;        if(n > m) swap(n, m);        printf("%d\n", solve(n, m));    }    return 0;}
1 0
原创粉丝点击