bzoj1101/洛谷P3455 [POI2007]ZAP-Queries
阿新 • • 發佈:2018-11-07
之前看了但是沒有理解的莫比烏斯函式現在找題目練練手。。。
寒假裡面看的當時理解不了就沒有多管,導致現在寫預處理函式很懵逼。。
題意:給定n,m,d,求出1<=x<=n,1<=y<=m中使得gcd(x,y)=d的x,y的對數
最簡單的方法,O(n²)的暴力列舉就不用說了,但是這個資料範圍肯定是過不了的。。
那麼我們設函式f(d)為使得gcd(x,y)=d的x,y的對數
設函式F(d)為d可以整除gcd(x,y)的情況
那麼顯然有(仔細想一下或者手玩一下)
則
反演之後就是
那麼我們先預處理μ的在範圍內的值然後每次求一下F(d),那麼就可以在根號時間內求出f(d)
程式碼:
在洛谷裡面如果計算的那裡不寫成函式的話就過不了。。也不知道怎麼回事就是TLE
//Decision's template #include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; #define DP_maxn 16 #define maxn 100000 #define INF 10000007 #define mod 1000000007 #define mst(s,k) memset(s,k,sizeof(s)) typedef long long ll; struct Edge{ int from,to,dist; Edge(int u,int v,int d):from(u),to(v),dist(d){} }; /*---------------------------template End----------------------------*/ int n,a,b,d,ans,mu[maxn],vis[maxn],p[maxn],top = 0,x = 0,i,j; void mobius() { int N = 50000; mu[1]=1; for(i=2;i<=N;++i) { if(!vis[i]) { mu[i]=-1;p[++top]=i; } for(j=1;(n=i*(x=p[j]))<=N;j++) { vis[n]=1; if(i%x) mu[n]=mu[i]*mu[x]; else break; } } for(i=2;i<=N;++i) mu[i]+=mu[i-1]; } ll cal(int n,int m) { ll ans = 0; top = min(a,b); i = 1; for(i = 1;i<=top;i = j+1) { j = min(a/(a/i),b/(b/i)); ans += (ll)(mu[j]-mu[i-1])*(a/i)*(b/i); } return ans; } int main() { //ios::sync_with_stdio(false); //freopen("std.in","r",stdin); //freopen("std.out","w",stdout); mobius(); cin>>n; while(n--) { ans = 0; cin>>a>>b>>d; a/=d,b/=d; cout<<cal(a,b)<<endl; } return 0; }