洛谷P3455 [POI2007]ZAP-Queries
阿新 • • 發佈:2020-10-29
題目連結
https://www.luogu.com.cn/problem/P3455
思路
簡單來說,就是求\(\displaystyle \sum^{a}_{i=1}{\sum^{b}_{j=1}{[gcd(i,j)==d}]}\),不妨令a<b。
那麼很容易想到,將\(a\)和\(b\)都除以\(d\),就只要求互質的數對了,就是\(\displaystyle \sum^{a/d}_{i=1}{\sum^{b/d}_{j=1}{[gcd(i,j)==1]}}\)
然後就是反演題常規套路,列舉g=gcd(i,j),一通亂搞搞出\(\displaystyle \sum^{a}_{D=1}{\lfloor \frac{a}{D}\rfloor \lfloor \frac{b}{D}\rfloor}\)
程式碼
#include<cstdlib> #include<algorithm> #define maxn (int)(5*1e4+10) using namespace std; int u[maxn],book[maxn],s[maxn],p[maxn],cnt=0; int main(){ int n,i,j,a,b,d,l,r; scanf("%d",&n); u[0]=0;u[1]=1; for(i=2;i<maxn;++i){ if(!book[i]){ u[i]=-1; p[++cnt]=i; } for(j=1;p[j]*i<maxn&&j<=cnt;++j){ book[i*p[j]]=1; if(!(i%p[j])) break; u[i*p[j]]=-u[i]; } } for(i=1;i<maxn;++i) s[i]=s[i-1]+u[i]; for(i=1;i<=n;++i){ scanf("%d%d%d",&a,&b,&d); if(a>b) swap(a,b); a/=d;b/=d; int ans=0; for(l=r=1;l<=a;l=r+1,r=min(a/(a/l),b/(b/l))){ ans+=(a/l)*(b/l)*(s[r]-s[l-1]); if(r==a) break; } printf("%d\n",ans); } // system("pause"); return 0; }