BZOJ 2301 [HAOI2011]Problem b 【莫比乌斯反演】
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
HINT
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
Solution
题意:如描述
题目和 BZOJ 1101 很像,只有 x , y 的取值范围又增加了一些限制
现在我们已经会求任意1<=x<=a,1<=y<=b,满足gcd( x,y ) = d 的(x,y)对数,设为 calc ( a,b )
于是用容斥推一下
答案应该是 calc( b,d ) - calc( a,d ) - calc( b,c ) + calc( a,c )
1 #include<map> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<climits> 8 #include<iomanip> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 14 #define maxp 50000 15 #define maxn 50000+5 16 #define set(a,b) memset(a,(b),sizeof(a)) 17 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++) 18 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--) 19 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next) 20 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next) 21 22 using namespace std; 23 24 typedef long long ll; 25 26 int prime[maxn],pri[maxn],tot=0; 27 int sum[maxn],miu[maxn]; 28 int ans; 29 int n,m; 30 31 void read() 32 { 33 #ifndef ONLINE_JUDGE 34 freopen("2301.in","r",stdin); 35 freopen("2301.out","w",stdout); 36 #endif 37 //cin >> n ; 38 scanf("%d",&n); 39 } 40 41 void write() 42 {} 43 44 void print() 45 { 46 //cout << ans << endl ; 47 printf("%d\n",ans); 48 } 49 50 void mobius() 51 { 52 miu[1]=1; 53 fr(i,2,maxp){ 54 if( !prime[i] ) pri[++tot]=i,miu[i]=-1; 55 int j=1; 56 while( j<=tot && pri[j]*i<=maxp ){ 57 prime[pri[j]*i]=1; 58 if( i%pri[j]==0 ){ 59 miu[pri[j]*i]=0; 60 break; 61 } 62 miu[pri[j]*i]=-miu[i]; 63 j++; 64 } 65 } 66 fr(i,1,maxp) 67 sum[i]=sum[i-1]+miu[i]; 68 } 69 70 int calc(int x,int y) 71 { 72 int res=0,pos,i=1; 73 if(x>y) swap(x,y); 74 while(i<=x){ 75 pos=min(x/(x/i),y/(y/i)); 76 res+=(sum[pos]-sum[i-1])*(x/i)*(y/i); 77 i=pos+1; 78 } 79 return res; 80 } 81 82 void work() 83 { 84 mobius(); 85 fr(i,1,n){ 86 int a,b,c,d,k; 87 //cin >> a >> b >> d ; 88 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 89 ans=calc((a-1)/k,(c-1)/k)+calc(b/k,d/k)-calc((a-1)/k,d/k)-calc(b/k,(c-1)/k); 90 print(); 91 } 92 } 93 94 int main() 95 { 96 read(); 97 work(); 98 write(); 99 return 0; 100 }