有一张 n×m 的数表,其第 i 行第 j 列(1 <= i <= n, 1 <= j <= m)的数值为
能同时整除 i 和 j 的所有自然数之和。给定 a , 计算数表中不大于 a 的数之和。
对每组数据,输出一行一个整数,表示答案模2^31的值。
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> using namespace std; #define N 100050 #define M 100000 typedef unsigned int un; int prime[N],cnt,miu[N],ys[N],ysh[N],id[N]; un c[N],ans[N]; bool vis[N]; struct A { int id,n,m,a; bool operator < (const A &x) const { return a<x.a; } }q[N]; void fix(int x,un v) {for(;x<=M;x+=x&(-x)) c[x]+=v;} un inq(int x) {un re=0; for(;x;x-=x&(-x)) re+=c[x]; return re;} inline bool cmp(const int &x,const int &y) {return ysh[x]<ysh[y];} void init() { int i,j; miu[1]=1; for(id[1]=1,i=2;i<=M;i++) { if(!vis[i]) { prime[++cnt]=i; miu[i]=-1; } for(j=1;j<=cnt&&i*prime[j]<=M;j++) { int y=i*prime[j]; vis[y]=1; if(i%prime[j]==0) {miu[y]=0;break;} miu[y]=-miu[i]; } id[i]=i; } for(i=1;i<=M;i++) for(j=i;j<=M;j+=i) ysh[j]+=i; sort(id+1,id+M+1,cmp); } void add(int x) { int i; for(i=x;i<=M;i+=x) { fix(i,ysh[x]*miu[i/x]); } } un solve(un n,un m) { int i,lst; if(n>m) swap(n,m); un re=0; for(i=1;i<=n;i=lst+1) { lst=min(n/(n/i),m/(m/i)); re+=(n/i)*(m/i)*(inq(lst)-inq(i-1)); } return re; } int main() { init(); int Q; scanf("%d",&Q); int i,j=1; for(i=1;i<=Q;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].id=i; sort(q+1,q+Q+1); for(i=1;i<=Q;i++) { while(ysh[id[j]]<=q[i].a&&j<=M) add(id[j]),j++; ans[q[i].id]=solve(q[i].n,q[i].m); } for(i=1;i<=Q;i++) printf("%u\n",ans[i]&((1u<<31)-1)); }
BZOJ_3529_[Sdoi2014]数表_莫比乌斯反演+树状数组
原文:https://www.cnblogs.com/suika/p/9429704.html