题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3529
题意:有一张n×m的数表,其第i行第j列的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。
思路:首先求出每个数字的约数之和,(i,sumFactor[i]),将这些二元组升序排序,将所有sumFactor小于等于a的插入树状数组,插入时,add(j*i,mou[j]*sumFactor[i]).
struct node { int n,m,id; i64 a; }; node a[N]; pair<i64,int> b[N]; int n,m; i64 sum[N]; int cmp(node a,node b) { return a.a<b.a; } i64 ans[N],S[N]; void add(int x,i64 y) { while(x<N) S[x]+=y,x+=x&-x; } i64 get(int x) { i64 ans=0; while(x) ans+=S[x],x-=x&-x; return ans; } int id; void Add(i64 x) { while(id+1<N&&b[id+1].first<=x) { id++; int j; for(j=1;j*b[id].second<N;j++) { add(j*b[id].second,b[id].first*mou[j]); } } } void cal(int t) { int n=a[t].n; int m=a[t].m; int L,R; for(L=1;L<=n&&L<=m;L=R+1) { R=min(n/(n/L),m/(m/L)); ans[a[t].id]+=(get(R)-get(L-1))*(n/L)*(m/L); } } int main() { initMou(); int i,j; for(i=1;i<N;i++) { for(j=i;j<N;j+=i) sum[j]+=i; } for(i=1;i<N;i++) b[i]=MP(sum[i],i); sort(b+1,b+N); RD(n); FOR1(i,n) RD(a[i].n,a[i].m),RD(a[i].a),a[i].id=i; sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++) { Add(a[i].a); cal(i); } for(i=1;i<=n;i++) printf("%d ",ans[i]&0x7fffffff); }