[省選集訓2022] 模擬賽15
阿新 • • 發佈:2022-03-20
Lost
題目描述
定義布林函式 \(f(x)\) 表示 \(x\) 是否為完全平方數,給定 \(n,m\),求:
\[\sum_{i=1}^n\sum_{j=1}^m f(ij) \]\(n,m\leq 10^{12}\)
解法
我們向深入考察 \(f(ij)\) 的性質,考慮 \(ij\) 為完全平方數的充要條件是,存在唯一的 \(d\) 滿足 \(i=dx^2,j=dy^2\),考慮 \(d\) 是一個只包含一次質因子的數,所以可以列舉 \(d\):
\[\sum_{d=1}^{n}\sqrt{\frac{n}{d}}\cdot\sqrt{\frac{m}{d}}\cdot \mu(d)^2 \]考慮對 \(u(d)^2\)
按照套路可以列舉 \(i\) 來化簡這個式子:
\[\sum_{i=1}^{\sqrt n}\mu(i)\sum_{d}\sqrt{\frac{n/i^2}{d}}\cdot\sqrt {\frac{m/i^2}{d}} \]注意根號的時候要強轉 \(\tt ll\)
補充:直接對 \(d\) 不包含平方因子這個條件做莫比烏斯反演,也可以得到最後的式子。
#include <cstdio> #include <iostream> #include <cmath> using namespace std; const int M = 1000005; #define int long long int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,cnt,ans,vis[M],p[M],mu[M]; void init(int n) { mu[1]=1; for(int i=2;i<=n;i++) { if(!vis[i]) p[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt && i*p[j]<=n;j++) { vis[i*p[j]]=1; if(i%p[j]==0) break; mu[i*p[j]]=-mu[i]; } } } int work(int n,int m) { int res=0; for(int l=1,r=1;l<=n;l=r+1) { r=min(n/(n/l),m/(m/l)); res+=(r-l+1)*(int)sqrt(n/l)*(int)sqrt(m/l); } return res; } signed main() { freopen("lost.in","r",stdin); freopen("lost.out","w",stdout); n=read();m=read();init(1e6); if(n>m) swap(n,m); for(int i=1,t=sqrt(n);i<=t;i++) if(mu[i]) ans+=mu[i]*work(n/i/i,m/i/i); printf("%lld\n",ans); }