GCD
Problem's Link
Mean:
给定五个数a,b,c,d,k,从1~a中选一个数x,1~b中选一个数y,使得gcd(x,y)=k.
求满足条件的pair(x,y)数.
analyse:
由于b,d,k都是1e5数量级的,普通枚举必定超时.
首先可以把b,d都同时除以k,问题就转化成了求1~b/k和1~d/k中的gcd(i,j)=k的对数.
证明如下:
令Ai∈{1,2,3...b},Bi∈{1,2,3...d}.
如果有:GCD(Ai,Bi)=k
则有:GCD(Ai/k,Bi/k)=1
而对于不能够被k整除的数,不可能有GCD(Ai,Bi)=k.
也就是说,除以K所剔除掉的数都是不满足条件的数,对最终答案没有影响.
这样就大大优化了时间复杂度.
然后就是对1e5以内的数进行质因数分解,使用质因数来构造容斥表.
再枚举1~b/k之间的每一个数,利用容斥原理算出1~d/k中有多少个数与之互质即可.
Time complexity: O(N*logN)
view code
/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-10-08-21.45
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define max(a,b) (a>b?a:b)
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);
const int NN = 100010;
bool v [NN ];
int p [NN ];
void makePrime()
{
int num =- 1 , i , j;
for( i = 2; i <NN; ++ i)
{
if( ! v [ i ]) { p [ ++ num ] = i; }
for( j = 0; j <= num && i *p [ j ] <NN; ++ j)
{
v [ i *p [ j ]] = true;
if( i %p [ j ] == 0) { break; }
}
}
}
struct node
{
int fac;
bool ti;
node() {}
node( int a , bool b) : fac( a ), ti(b) {}
};
vector < node > pa [NN ];
void pre()
{
int i , j , a , cnt , si;
for( i = 1; i <= 100000; ++ i)
{
a = i;
cnt = 0;
for( j = 0; j <= 9672; ++ j)
{
if( !( a %p [ j ]))
{
pa [ i ]. push_back( node(p [ j ], false));
si = pa [ i ]. size();
for( int k = 0; k < si - 1; ++ k)
{
pa [ i ]. push_back( node( pa [ i ][ si - 1 ]. fac * pa [ i ][ k ]. fac , ! pa [ i ][ k ]. ti));
}
while( !( a %p [ j ]))
a /=p [ j ];
}
if(p [ j ] > a || a <= 0) break;
}
}
}
int main()
{
makePrime();
pre();
ios_base :: sync_with_stdio( false);
cin . tie( 0);
int t;
scanf( "%d" , & t);
for( int Cas = 1; Cas <= t; ++ Cas)
{
int a ,b , c , d , k , si;
scanf( "%d %d %d %d %d" , & a , &b , & c , & d , & k);
if( k == 0)
{
printf( "Case %d: 0 \n " , Cas);
continue;
}
a =b / k;
b = d / k;
if( a >b) swap( a ,b);
LL ans =b;
if( a == 0) ans = 0;
for( int i = 2; i <= a; ++ i)
{
si = pa [ i ]. size();
for( int j = 0; j < si; ++ j)
{
if( !( pa [ i ][ j ]. ti))
{
ans +=((b - i + 1) -b / pa [ i ][ j ]. fac +( i - 1) / pa [ i ][ j ]. fac);
}
else
{
ans -=((b - i + 1) -b / pa [ i ][ j ]. fac +( i - 1) / pa [ i ][ j ]. fac);
}
}
}
printf( "Case %d: %I64d \n " , Cas , ans);
}
return 0;
}
/*
*/
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-10-08-21.45
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define max(a,b) (a>b?a:b)
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);
const int NN = 100010;
bool v [NN ];
int p [NN ];
void makePrime()
{
int num =- 1 , i , j;
for( i = 2; i <NN; ++ i)
{
if( ! v [ i ]) { p [ ++ num ] = i; }
for( j = 0; j <= num && i *p [ j ] <NN; ++ j)
{
v [ i *p [ j ]] = true;
if( i %p [ j ] == 0) { break; }
}
}
}
struct node
{
int fac;
bool ti;
node() {}
node( int a , bool b) : fac( a ), ti(b) {}
};
vector < node > pa [NN ];
void pre()
{
int i , j , a , cnt , si;
for( i = 1; i <= 100000; ++ i)
{
a = i;
cnt = 0;
for( j = 0; j <= 9672; ++ j)
{
if( !( a %p [ j ]))
{
pa [ i ]. push_back( node(p [ j ], false));
si = pa [ i ]. size();
for( int k = 0; k < si - 1; ++ k)
{
pa [ i ]. push_back( node( pa [ i ][ si - 1 ]. fac * pa [ i ][ k ]. fac , ! pa [ i ][ k ]. ti));
}
while( !( a %p [ j ]))
a /=p [ j ];
}
if(p [ j ] > a || a <= 0) break;
}
}
}
int main()
{
makePrime();
pre();
ios_base :: sync_with_stdio( false);
cin . tie( 0);
int t;
scanf( "%d" , & t);
for( int Cas = 1; Cas <= t; ++ Cas)
{
int a ,b , c , d , k , si;
scanf( "%d %d %d %d %d" , & a , &b , & c , & d , & k);
if( k == 0)
{
printf( "Case %d: 0 \n " , Cas);
continue;
}
a =b / k;
b = d / k;
if( a >b) swap( a ,b);
LL ans =b;
if( a == 0) ans = 0;
for( int i = 2; i <= a; ++ i)
{
si = pa [ i ]. size();
for( int j = 0; j < si; ++ j)
{
if( !( pa [ i ][ j ]. ti))
{
ans +=((b - i + 1) -b / pa [ i ][ j ]. fac +( i - 1) / pa [ i ][ j ]. fac);
}
else
{
ans -=((b - i + 1) -b / pa [ i ][ j ]. fac +( i - 1) / pa [ i ][ j ]. fac);
}
}
}
printf( "Case %d: %I64d \n " , Cas , ans);
}
return 0;
}
/*
*/