1. 程式人生 > >[BZOJ 2301] Problem B

[BZOJ 2301] Problem B

sdi sum color strong void pri atom .org 需要

Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2301

Algorithm:

分析:令g(n,m)表示在1<=x<=n,1<=y<=m,滿足gcd(x,y)是k的(x,y)的對數。
那麽由容斥原理可得

ans=g(b,d)+g(a?1,c-1)?g(a-1,d)-g(b,c?1,k)


滿足gcd(x,y)是k的(x,y)的對數也等價於1<=x<=n/k,1<=y<=m/k,(x,y)互質的對數,即

g(n,m,k)=g(n/k,m/k,1)


令f(i)表示滿足gcd(x,y)=i時(x,y)的對數

F(i)表示滿足i|gcd(x,y)的(x,y)的對數,則F(i)=?ni??mi?

於是我們發現這是一個具有倍數關系的莫比烏斯反演: F(i)=Σ{i|d} f(d) <-----> f(i)=Σ{i|d} miu(d/i)*(n/d)*(m/d) 接下來就要優化每次求f(i)的復雜度,需要將其降至O(logN),

發現[n/d] 最多有2sqrt(n) 個取值,那麽 (n/d)*(m/d)就至多有2sqrt(n)+2sqrt(m)個取值(並不是*,對於每個d n/(sqrt(n)+1)<d<=n , (n/d)*(m/d)仍只有一個值)

於是我們發現會有連續的一段(n/d)*(m/d)的值相同,便可以使用分塊來優化(細節待填坑)

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=5e4+10;
inline ll read()
{
    char ch;ll num,f=0;
    while(!isdigit(ch=getchar())) f|=(ch==-);
    num=ch-0;
    while(isdigit(ch=getchar())) num=num*10+ch-0;
    return f?-num:num;
}

int a,b,c,d,k;
int sum[MAXN],mo[MAXN],pri[MAXN],cnt; bool mark[MAXN]; void getmo() { mo[1]=1; for(int i=2;i<=5e4;i++) { if(!mark[i]){mo[i]=-1;pri[++cnt]=i;} for(int j=1;j<=cnt && i*pri[j]<=5e4;j++) { mark[i*pri[j]]=1; if(i%pri[j]==0){mo[i*pri[j]]=0;break;} else mo[i*pri[j]]=-mo[i]; } } for(int i=1;i<=5e4;i++) sum[i]=sum[i-1]+mo[i]; } int cal(int n,int m) { n/=k;m/=k; if(n>m)swap(n,m); int ret=0,pos; for(int i=1;i<=n;i=pos+1) { pos=min(n/(n/i),m/(m/i)); ret+=(sum[pos]-sum[i-1])*(n/i)*(m/i); } return ret; } int main() { getmo(); int T=read(); while(T--) { a=read();b=read();c=read();d=read();k=read(); int res=cal(a-1,c-1)+cal(b,d)-cal(a-1,d)-cal(b,c-1); printf("%d\n",res); } return 0; }

Review:

1、GCD(x,y)=k --------> x/k,y/k互質

方便使用歐拉函數或莫比烏斯反演解題

2、使用分塊對莫比烏斯反演的優化(待填)

[BZOJ 2301] Problem B