洛谷P3312 - [SDOI2014]数表

Portal

Solution

\(T(T\leq2\times10^4)\)组测试数据。给出\(n,m(n,m\leq10^5),a(a\leq10^9)\),求$$ \sum_{i=1}n\sum_{j=1}m [\sigma_1(gcd(i,j))\leq a]\sigma_1(gcd(i,j)) $$

Solution

\[\begin{align*} ans &= \sum_{i=1}^n\sum_{j=1}^m [\sigma_1(gcd(i,j))\leq a]\sigma_1(gcd(i,j)) \\ &= \sum_{d=1}^{+∞} [\sigma_1(d)\leq a]\sigma_1(d) \sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=d] \\ &= \sum_{d=1}^{+∞} [\sigma_1(d)\leq a]\sigma_1(d) \sum_{d_1=1}^{+∞} \mu(d_1)⌊\frac{n}{dd_1}⌋⌊\frac{m}{dd_1}⌋ \\ &= \sum_{d=1}^{+∞} ⌊\frac{n}{d}⌋⌊\frac{m}{d}⌋ \sum_{d_1|d} [\sigma_1(d_1)\leq a]\sigma_1(d_1)\mu(\frac{d}{d_1}) \end{align*}$$ 将测试数据按$a$由小到大排序,维护$f(x)=\sum_{d|x} [\sigma_1(d)\leq a]\sigma_1(d)\mu(\dfrac{x}{d})$的前缀和。当$a$由$a_1$增大至$a_2$时,对于$d$满足$\sigma_1(d)\in(a_1,a_2]$,将$\sigma_1(d)\mu(k)$加到$f(kd)$中。预处理出$\sigma_1(x),\mu(x)$,用树状数组维护$f(x)$的前缀和即可。 > 时间复杂度$O(n+T\sqrt n+nlogn)$。 ##Code ```cpp //[SDOI2014]数表 #include <algorithm> #include <cstdio> using namespace std; inline char gc() { static char now[1<<16],*s,*t; if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;} return *s++; } inline int read() { int x=0; char ch=gc(); while(ch<'0'||'9'<ch) ch=gc(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc(); return x; } const int N=1e5+10; const int N1=1e5; int pCnt,pr[N],p1[N]; bool pNot[N]; int mu[N]; struct rec{int v,id;} f[N]; bool cmpV(rec x,rec y) {return x.v<y.v;} void init(int n) { mu[1]=1,f[1].v=1; for(int i=1;i<=n;i++) f[i].id=i; for(int i=2;i<=n;i++) { if(!pNot[i]) { pr[++pCnt]=i; p1[i]=i; mu[i]=-1,f[i].v=i+1; for(long long j=1LL*i*i;j<=n;j*=i) f[j].v=f[j/i].v*i+1; } for(int j=1;j<=pCnt;j++) { int x=i*pr[j]; if(x>n) break; pNot[x]=true; if(i%pr[j]) p1[x]=pr[j],mu[x]=-mu[i],f[x].v=f[i].v*(pr[j]+1); else {p1[x]=p1[i]*pr[j],f[x].v=f[x/p1[x]].v*f[p1[x]].v; break;} } } sort(f+1,f+n+1,cmpV); } struct query{int n,m,a,id;} q[20010]; bool cmpA(query x,query y) {return x.a<y.a;} int tr[N]; void add(int x,int v) {while(x<=N1) tr[x]+=v,x+=x&(-x);} int sum(int x) {int r=0; while(x) r+=tr[x],x-=x&(-x); return r;} int ans[20010]; int main() { int Q=read(); init(N1); for(int i=1;i<=Q;i++) q[i].n=read(),q[i].m=read(),q[i].a=read(),q[i].id=i; sort(q+1,q+Q+1,cmpA); for(int i=1,j=1;i<=Q;i++) { int n=q[i].n,m=q[i].m,a=q[i].a; while(j<=1e5&&f[j].v<=a) { int d1=f[j].id; for(int k=1;k*d1<=1e5;k++) add(k*d1,f[j].v*mu[k]); j++; } if(n>m) swap(n,m); int res=0; for(int L=1,R;L<=n;L=R+1) { int v1=n/L,v2=m/L; R=min(n/v1,m/v2); res+=v1*v2*(sum(R)-sum(L-1)); } ans[q[i].id]=res&2147483647; } for(int i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0; } ``` ##P.S. 答案对$2147483647$取模,这就相当于自然溢出然后`&2147483647`。\]

posted @ 2018-05-06 17:01  VisJiao  阅读(324)  评论(0编辑  收藏  举报