bzoj2301(莫比乌斯反演)
经典题。首先得知道最基本的莫比乌斯求1-n和1-m之间有多少互质对
然后根据下面论文
http://wenku.baidu.com/view/fbe263d384254b35eefd34eb.html
将每次查询的时间优化为n^(0.5)
妙啊 妙啊
还有要注意的一点,a,b,c,d不能在最开始的时候就除k
不然的话对于k!=1时,会出错
// // main.cpp // bzoj2301 // // Created by New_Life on 16/7/6. // Copyright © 2016年 chenhuan001. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> using namespace std; #define N 100100 //--莫比乌斯反演函数--// //说明:利用线性素数筛选顺便求了个mu //复杂度:O(n) int mu[N]; void mobus() { bool mark[N]; int prime[N]; int pcnt=0; memset(mark,0,sizeof(mark)); mu[1] = 1; for(int i=2;i<N;i++) { if(mark[i] == 0) { prime[pcnt++] = i; mu[i] = -1; } for(int j=0;j<pcnt && i*prime[j]<N;j++) { int tmp = i*prime[j]; mark[tmp] = 1; if( i%prime[j] == 0 ) { mu[tmp] = 0; break; } mu[tmp] = mu[i]*-1; } } } int sum[N]; long long gaobili(int b,int d) { if(b<=0||d<=0) return 0; int m = min(b,d); long long ans = 0; while(m>=1) { int tb = b/( b/m +1 )+1; int td = d/( d/m +1 )+1; //前进的最大位置 int tm = max(tb,td); ans += (long long)(sum[m]-sum[tm-1])*(b/m)*(d/m); m = tm-1; } return ans; } int main() { mobus(); for(int i=1;i<N;i++) sum[i] += sum[i-1]+mu[i]; int T; cin>>T; while(T--) { int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); //a/=k; b/=k; c/=k; d/=k;//这里很关键 //搞bd long long ans = gaobili(b/k, d/k)-gaobili((a-1)/k, d/k)-gaobili(b/k, (c-1)/k)+gaobili((a-1)/k, (c-1)/k); printf("%lld\n",ans); } return 0; } /* 2 2 5 1 5 1 1 5 1 5 2 */