【51nod】1222 最小公倍數計數 莫比烏斯反演+組合計數
阿新 • • 發佈:2018-03-02
ace using 復雜度 amp nebula names ons 問題 sin
【題意】給定a和b,求滿足a<=lcm(x,y)<=b && x<y的數對(x,y)個數。a,b<=10^11。
【算法】莫比烏斯反演+組合計數
【題解】★具體推導過程參考:51nod1222 最小公倍數計數
過程運用到的技巧:
1.將所有i和j的已知因子提取出來壓縮上屆。
2.將帶有μ(k)的k提到最前面,從而後面變成單純的三元組形式。
最終形式:
$$ans=\sum_{k=1}^{\sqrt n} \mu(k) \sum_{d} \sum_{i} \sum_{j} [i*j*d<=\frac{n}{k^2}]$$
問題轉化為枚舉(d,i,j)三元組滿足其乘積<=n/k^2。
雖然題目要求組合(有序),但是有d的存在,所以先求排列(無序)。
但是三元組的排列不方便統計,所以求三元組的組合乘上排列系數
先算嚴格從小到大的,然後減去兩個相同的和三個相同的。
最後+n後/2就變成組合。
聽說復雜度O(n^(2/3))。
#include<cstdio> #include<cmath> #define int long long using namespace std; const int maxn=1000010; int miu[maxn],prime[maxn],tot; bool vis[maxn]; int solve(int x){ ifView Code(!x)return 0; int N=(int)sqrt(x)+1,ans=0; for(int k=1;k<=N;k++)if(miu[k]){ int n=x/(k*k); for(int d=1;d*d*d<=n;d++){ for(int i=d+1;i*i*d<=n;i++)ans+=miu[k]*((n/(d*i)-i)*6+3); ans+=miu[k]*((n/(d*d)-d)*3+1); } } return (ans+x)/2; }#undef int int main(){ #define int long long int A,B; scanf("%lld%lld",&A,&B); int N=(int)sqrt(B)+1; miu[1]=1; for(int i=2;i<=N;i++){ if(!vis[i]){miu[prime[++tot]=i]=-1;} for(int j=1;j<=tot&&i*prime[j]<=N;j++){ vis[i*prime[j]]=1;// if(i%prime[j]==0)break; miu[i*prime[j]]=-miu[i]; } } printf("%lld\n",solve(B)-solve(A-1)); return 0; }
【51nod】1222 最小公倍數計數 莫比烏斯反演+組合計數