[BZOJ1101][POI2007]Zap

Description

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

Input

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

Output

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

Sample Input

2
4 5 2
6 4 3

Sample Output

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

 


写多了发现全是套路...

就是需要一个前缀和优化...什么整除分块什么的,昨天晚上做了余数求和那道题貌似就是除法分块。

好高深。

还有为什么不开long long 比 开 块一倍多, 又是玄学?

开long longTLE了,换成int过了233


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
inline int read(){
    int res=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res;
}
int T, n, a, b, d;
int prime[50005], miu[50005], cnt;
bool vis[50005];
int qzh[50005];

signed main()
{
    T = read();
    n = 50000;
    miu[1] = 1;
    for (int i = 2 ; i <= n ; i ++)
    {
        if (!vis[i]) prime[++cnt] = i, miu[i] = -1;
        for (int j = 1 ; j <= cnt and i * prime[j] <= n ; j ++)
        {
            vis[i*prime[j]] = 1;
            if (i % prime[j] == 0) break;
            miu[i*prime[j]] = - miu[i];
        }
    }
    for (int i = 1 ; i <= n ; i ++) qzh[i] = qzh[i-1] + miu[i];    
    while(T--)
    {
        a = read(), b = read(), d = read();
        int ans = 0;
        a=a/d, b=b/d;
        for (int i = 1, gx ; i <= min(a, b) ; i = gx + 1)
        {
            gx = min(a/(a/i), b/(b/i));
            ans += (a/i)*(b/i)*(qzh[gx]-qzh[i-1]);
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zZh-Brim/p/9415778.html