[SDOI2014]数表

题目大意:
  $q(q\leq2\times10^4)$组询问,每次对于给定的$n,m,a(n,m\leq10^5,a\leq10^9)$,求$\displaystyle\sum_{i=1}^n\sum_{j=1}^m[\sigma(\gcd(i,j))\leq a]\sigma(\gcd(i,j))$。

思路:
  首先不考虑$a$的限制,原式=$\displaystyle\sum_{d=1}^{\min(n,m)}\sigma(d)\sum_{p=1}^{\min(\lfloor\frac n d\rfloor,\lfloor\frac m d\rfloor)}\mu(p)\lfloor\frac n{dp}\rfloor\lfloor\frac m{dp}\rfloor$。
  令$T=dp$,则原式=$\displaystyle\sum_{T=1}^{\min(n,m)}\lfloor\frac n T\rfloor\lfloor\frac m T\rfloor\sum_{d|T}\sigma(d)\mu(\frac T d)$。
  设$\displaystyle g(T)=\sum_{d|T}\sigma(d)\mu(\frac T d)$,原式=$\displaystyle\sum_{T=1}^{\min(n,m)}\lfloor\frac n T\rfloor\lfloor\frac m T\rfloor g(T)$。
  其中$g(T)$可以线性筛,求和可以数论分块。
  考虑加入$a$的限制。按$a$的顺序离线处理询问,维护一个树状数组,其中第$i$位上的值$t_i$表示$g(i)$中$\sigma(d)\leq a$的数之和。可以先将所有的$\sigma(d)$排序,然后每组询问把$\leq a$的$\sigma(d)$乘上对应的$\mu$加入即可。

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<climits>
  4 #include<algorithm>
  5 inline int getint() {
  6     register char ch;
  7     while(!isdigit(ch=getchar()));
  8     register int x=ch^'0';
  9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 10     return x;
 11 }
 12 const int Q=2e4,N=1e5+1,P=9593;
 13 struct Query {
 14     int n,m,a,id;
 15     bool operator < (const Query &another) const {
 16         return a<another.a;
 17     }
 18 };
 19 Query q[Q];
 20 struct Func {
 21     int x,y;
 22     bool operator < (const Func &another) const {
 23         return y<another.y;
 24     }
 25 };
 26 Func sigma[N];
 27 bool vis[N];
 28 int ans[Q],p[P],mu[N];
 29 inline void sieve() {
 30     mu[1]=1;
 31     for(register int i=2;i<N;i++) {
 32         if(!vis[i]) {
 33             p[++p[0]]=i;
 34             mu[i]=-1;
 35         }
 36         for(register int j=1;j<=p[0]&&i*p[j]<N;j++) {
 37             vis[i*p[j]]=true;
 38             if(i%p[j]==0) {
 39                 mu[i*p[j]]=0;
 40                 break;
 41             }
 42             mu[i*p[j]]=-mu[i];
 43         }
 44     }
 45     for(register int i=1;i<N;i++) {
 46         sigma[i].x=i;
 47         for(register int j=i;j<N;j+=i) {
 48             sigma[j].y+=i;
 49         }
 50     }
 51     std::sort(&sigma[1],&sigma[N]);
 52 }
 53 class FenwickTree {
 54     private:
 55         int val[N];
 56         int lowbit(const int &x) const {
 57             return x&-x;
 58         }
 59     public:
 60         void modify(int p,const int &x) {
 61             while(p<N) {
 62                 val[p]+=x;
 63                 p+=lowbit(p);
 64             }
 65         }
 66         int query(int p) const {
 67             int ret=0;
 68             while(p) {
 69                 ret+=val[p];
 70                 p-=lowbit(p);
 71             }
 72             return ret;
 73         }
 74 };
 75 FenwickTree t;
 76 int main() {
 77     sieve();
 78     const int cnt_q=getint();
 79     for(register int i=0;i<cnt_q;i++) {
 80         const int n=getint(),m=getint(),a=getint();
 81         q[i]=(Query){n,m,a,i};
 82     }
 83     std::sort(&q[0],&q[cnt_q]);
 84     for(register int i=0,cur=1;i<cnt_q;i++) {
 85         for(;cur<N&&sigma[cur].y<=q[i].a;cur++) {
 86             for(register int j=sigma[cur].x;j<N;j+=sigma[cur].x) {
 87                 t.modify(j,sigma[cur].y*mu[j/sigma[cur].x]);
 88             }
 89         }
 90         const int &n=q[i].n,&m=q[i].m,&id=q[i].id,lim=std::min(n,m);
 91         for(register int i=1,j;i<=lim;i=j+1) {
 92             j=std::min(n/(n/i),m/(m/i));
 93             ans[id]+=(t.query(j)-t.query(i-1))*(n/i)*(m/i);
 94         }
 95     }
 96     for(register int i=0;i<cnt_q;i++) {
 97         printf("%d\n",ans[i]&INT_MAX);
 98     }
 99     return 0;
100 }

 

posted @ 2018-02-25 20:04  skylee03  阅读(127)  评论(0编辑  收藏  举报