然后按照f[i]和a分别排序之后离线插入用树状数组维护前缀和即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #define N 100005 using namespace std; int cnt,pt,mx,p[N],mu[N],c[N],prm[N],ans[N]; struct node{ int x,y,k,id; }a[N],f[N]; int read(){ int x=0,fu=1; char ch=getchar(); while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); } while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*fu; } void add(int x,int t){ for (; x<=mx; x+=x&-x) c[x]+=t; } int getsum(int x){ int t=0; for (; x; x-=x&-x) t+=c[x]; return t; } bool cmp(node u,node v){ return u.k<v.k; } void pfs(){ int i,j,k; f[1].k=f[1].id=mu[1]=1; for (i=2; i<=mx; i++){ f[i].id=i; if (!p[i]){ f[i].k=i+1; mu[i]=-1; prm[++cnt]=p[i]=i; } for (j=1; j<=cnt && i*prm[j]<=mx; j++){ k=i*prm[j]; if (i%prm[j]){ mu[k]=-mu[i]; p[k]=prm[j]; f[k].k=f[i].k*f[prm[j]].k; } else{ mu[k]=0; p[k]=p[i]*prm[j]; if (p[k]==k) f[k].k=f[i].k*prm[j]+1; else f[k].k=f[k/p[k]].k*f[p[k]].k; break; } } } sort(f+1,f+mx+1,cmp); } int main(){ pt=read(); int i; for (i=1; i<=pt; i++){ a[i].x=read(); a[i].y=read(); a[i].k=read(); a[i].id=i; if (a[i].x>a[i].y) swap(a[i].x,a[i].y); mx=max(mx,a[i].x); } pfs(); sort(a+1,a+pt+1,cmp); int j,k,now=1; for (i=1; i<=pt; i++){ for (; now<=mx && f[now].k<=a[i].k; now++) for (k=f[now].id; k<=mx; k+=f[now].id) add(k,f[now].k*mu[k/f[now].id]); int m=a[i].x,n=a[i].y,last=0,now=0; for (j=1; j<=m; j=k+1,last=now){ k=min(m/(m/j),n/(n/j)); now=getsum(k); ans[a[i].id]+=(now-last)*(m/j)*(n/j); } } for (i=1; i<=pt; i++) printf("%d\n",ans[i]&2147483647); return 0; }
by lych
2016.4.4