您的位置:首页 > 其它

BZOJ1101: [POI2007]Zap

2014-09-07 11:21 405 查看

1101: [POI2007]Zap

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1268 Solved: 399
[Submit][Status]

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

HINT

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

Source

题解:

贾志鹏线性筛。

分块的技巧基于:

n/(n/i)为 拥有 n/j=n/i 性质的最大的j ,也就是从i --n/(n/i)这一段 n 除它们的商相等

比如 100/34=2 100/(100/34)=100/2=50 34-50这一段被n除的商都是2

为什么呢? 这是因为我们对100可以这样分解

100=34*2+32 32比34小,作为余数

100=2*50+0 0比2小,作为余数

也就是说,我们只要把第一次的除法的余数分配到(n/i)的系数上,就可以尽可能的保持,n/i不变,而它的系数尽可能大,显然不能在分过去的时候,n/i的系数达到的了最大。

而这刚好就是n/(n/i)

说了一堆废话。。。

代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define inf 1000000000
#define maxn 50000+1000
#define maxm 500+100
#define eps 1e-10
#define ll long long
#define pa pair<int,int>
#define for0(i,n) for(int i=0;i<=(n);i++)
#define for1(i,n) for(int i=1;i<=(n);i++)
#define for2(i,x,y) for(int i=(x);i<=(y);i++)
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
int p[maxn],mu[maxn],sum[maxn];
bool check[maxn];
void get()
{
int tot=0;
mu[1]=1;
for2(i,2,maxn)
{
if(!check[i])p[++tot]=i,mu[i]=-1;
for1(j,tot)
{
int k=p[j]*i;
if(k>maxn)break;
check[k]=1;
if(i%p[j])mu[k]=-mu[i];else {mu[k]=0;break;}
}
}
for1(i,maxn)sum[i]=sum[i-1]+mu[i];
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
get();
int cs=read();
while(cs--)
{
ll n=read(),m=read(),x=read(),ans=0;
n/=x;m/=x;
if(n>m)swap(n,m);
for(int s=1,t;s<=n;s=t+1)
{
t=min(n/(n/s),m/(m/s));
ans+=(n/s)*(m/s)*(sum[t]-sum[s-1]);
}
printf("%lld\n",ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: