【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=4135
http://acm.hdu.edu.cn/showproblem.php?pid=1695
【解题报告】
题目其实很简单,考虑到容斥需要的几个基本操作需要打熟练,就更新这么一篇blog上来。
hdu4135很裸。给出一个N,求A,B区间内和N互素的数都个数。那么我们如果知道有多少数和N不互质,取个反就ok了。所以把N**质因数分解**(其实我第一遍质因数分解写错了,所以T了一发,读者应该敲熟质因数分解,尽量避免手残现象的出现),求A,B之间以N的质因数为约数的数的总个数即可。这个过程可以用容斥求得,过程不再赘述。
hdu1695同样很裸,求两个区间A..B和C..D之间GCD为k的数对的个数,注意数对无序所以形似(5,7)和(7,5)的数对被认为是一个数对。
假设GCD(x,y)=k,其实我们只需要知道kGCD(x’,y’)=1的数对有多少个即可。要注意一点即kx’ in a..b; ky’ in c..d。
尤其注意,a和c已限定为1.
【参考代码:4135】
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
vector<LL>P;
LL N,A,B;
void getphi( LL N )
{
P.clear();
int k=2;
while( k*k<=N )
{
if( N%k==0 )
{
P.push_back( k );
while( N%k==0 )N/=k;
}
k++;
}
if( N>1 )P.push_back( N );
}
int GCD( int A, int B )
{
if( B==0 )return A;
else return GCD( B,A%B );
}
int LCM( int A, int B )
{
return A*B/GCD( A,B );
}
LL solve()
{
int L=P.size();
LL ans=0;
for( int i=1;i<(1<<L); i++ )
{
int cur=0,num=1;
for( int j=L-1; j>=0;j-- )if( (1<<j)&i )
{
num=LCM( num,P[j] );
cur++;
}
if( cur&1 ) ans+=(LL)B/num-(LL)(A-1)/num;
else ans-=(LL)B/num-(LL)(A-1)/num;
}
return (LL)B-(LL)A+1LL-ans;
}
void swaps( LL& A, LL& B ) { LL tmp=A; A=B; B=tmp; }
int main()
{
int T,kase=0; cin>>T;
while( T-- )
{
cin>>A>>B>>N;
if( A>B )swaps( A,B );
getphi( N );
// if( N==1 )P.push_back( 1 );
// for( int i=0; i<P.size(); i++ )cout<<P[i]<<endl;
cout<<"Case #"<<++kase<<": "<<solve()<<endl;
}
return 0;
}
【参考代码:1695】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
int a,b,c,d,k;
LL ans;
vector<int>P;
void getphi( int n )
{
P.clear();
int k=2;
while( k*k<=n ){
if( n%k==0 ){
P.push_back( k );
while( n%k==0 )n/=k;
}
k++;
}
if( n>1 )P.push_back(n);
}
int GCD( int x, int y ){ return y ? GCD(y,x%y) : x; }
int LCM( int x, int y ) { return x*y/GCD(x,y); }
LL solve()
{
LL ans=0;
for( int i=1; i<=b; i++ )
{
getphi(i);
int m=P.size();
for( int j=1; j<(1<<m); j++ )
{
int cur=0,num=1;
for( int k=0; k<m; k++ )if( (1<<k)&j )
{
num=LCM(num,P[k]);
cur++;
}
if( cur&1 )ans+=d/num-(i-1)/num;
else ans-=d/num-(i-1)/num;
}
}
return (LL)(d*2-b+1)*b/2-ans;
}
//d+d-1+...+(d-b+1) (d*2-b+1)b/2
int main()
{
int T,kase=0; scanf( "%d",&T );
while( T-- )
{
scanf( "%d%d%d%d%d",&a,&b,&c,&d,&k );
if(k==0){
printf( "Case %d: %lld\n",++kase,0 );
continue;
}
b/=k; d/=k;
if( b>d ) swap(b,d);
printf( "Case %d: %lld\n",++kase, solve( ));
}
return 0;
}