1325: A very hard problem
Time Limit: 3 Sec Memory Limit: 160 MBSubmit: 253 Solved: 58
[ Submit][ Status][ Web Board]
Description
CX老湿经常被人黑,被黑得多了,自己也就麻木了。于是经常听到有人黑他,他都会深情地说一句:禽兽啊!
一天CX老湿突发奇想,给大家出了一个难题,并且声称谁能够准确地回答出问题才能继续黑他,否则他就要反击了。
这个难题就是:
给出两个数p和q,接下来q个询问,每个询问给出两个数A和B,请分别求出:
一、有多少个有序数对(x,y)满足1<=x<=A,1<=y<=B,并且gcd(x,y)为p的一个约数;
二、有多少个有序数对(x,y)满足1<=x<=A,1<=y<=B,并且gcd(x,y)为p的一个倍数。
Input
只有一组测试数据。
第一行两个数:p和q。(1<p<10^7 ,1<q<1000。)
接下来有q行,每行两个数A和B。(1<A,B<10^7)
Output
输出共q行。每行两个数。用空格隔开。
分别表示题目描述中的两个对应的答案。
(x,y)=(2,3)和(x,y)=(3,2)被视为两个不同有序数对哦!
Sample Input
6 3
8 8
15 32
13 77
Sample Output
58 1
423 10
883 24
HINT
对于64位整型请用lld,或者cin,cout。T_T
CSU_LQ
Source
题目:求满足1<= a <= x, 1<= b <= y,,gcd(a,b)是p的约数的,a,b的组合数。
分析:
第二问直接除法就行
第一问,用莫比乌斯可以再X^0.5内可以求出关于某个gcd的组合数:不会的话参考匡斌的博客,
下面两个题目也是莫比乌斯的,通过这两个题目就可以搜到kuangbin的博客,然后看相关的资料
http://www.cnblogs.com/kuangbin/archive/2013/08/21/3273440.html
下面是资料:
http://wenku.baidu.com/view/542961fdba0d4a7302763ad5.html
http://baike.baidu.com/link?url=1qQ-hkgOwDJAH4xyRcEQVoOTmHbiRCyZZ-hEJxRBQO8G0OurXNr6Rh6pYj9fhySI0MY2RKpcaSPV9X75mQv0hK
;以下是我写的两题莫比乌斯的博客:
http://blog.csdn.net/firenet1/article/details/47171991
http://blog.csdn.net/firenet1/article/details/47171991
看完以上两个博客,知道分块处理莫比乌斯可以根号的时间复杂度来做。----------但是需要预处理u函数的前缀和
分析;只要求出p的所有因素,对每个因数求有多少对a,b的gcd是它的就行,但是因素个数很多!
1000组case,还有根号的复杂度就是1000*sqrt(x)*C > 1000,000,000会超时,
那么考虑把所有的因素的预处理掉。
举例:如果1,2是p的因数
f(1) = u(1)* F*(1) + u(2) * F(2) + u(3) *F(3) + u(4)*F(4) + .....
f(2) = u (1) * F(1*2) + u(2) * F(2*2) +.......
可以发现如果把1,2的函数一起处理,那么需要把F(2),F(4),F(6).....的系数处理掉,那么
F(2)的系数就是u(1)+u(2)
F(4)的系数就是u(4)+u(2)
可以看出因子1需要处理O(p)(p是数据范围的意思)个系数
因子2需要处理O(p/2)个系数,那么总共的次数越是p*log(log(p))的
#include <iostream>
#include <string.h>
#include <cmath>
#include <stdio.h>
#define maxn 10000100
using namespace std;
int m,cnt;
long long n;
int mu[maxn];
int prime[maxn],vis[maxn];
int sum[maxn];
long long ans,sav[100000];
void init(){
memset(vis,0,sizeof(vis));
cnt=0;
mu[1]=1;
for(int i=2;i<maxn;i++){
if(!vis[i]){
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<maxn;j++){
vis[i*prime[j]]=1;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else {
mu[i*prime[j]]=0;
break;
}
}
}
//莫比乌斯函数
}
int main(){
long long a,b;
scanf("%lld%d",&n,&m);
init();
int k=0;
for(int i=1;i*i<=n;i++) //预处理因素
if(n%i==0){
sav[k++]=i;
if(i!=n/i)
sav[k++]=n/i;
}
memset(sum,0,sizeof(sum)); //合并所有因子对应的u函数的前缀和
for(int i = 0;i < k; i++){
for(int j = 1;j*sav[i] < maxn; j++)
sum[j*sav[i]] += mu[j];
}
for(int i = 1;i < maxn; i++){
sum[i] = sum[i-1] + sum[i];
}
for(int i=0;i<m;i++){
scanf("%lld%lld",&a,&b);
ans=0;
int N = a, M = b,l;
if(N > M) swap(N,M);
for(int j = 1; j <= N ;j = l + 1) //分快加速
{
l= min(N/(N/j),M/(M/j));
ans += (long long)(sum[l]-sum[j-1])*(N/j)*(M/j);
}
long long tmp=a/n;
tmp=b/n*tmp;
printf("%lld %lld\n",ans,tmp);
}
return 0;
}