Bzoj3529 [Sdoi2014]数表

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1653  Solved: 835

Description

    有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为
能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。

Input

    输入包含多组数据。
    输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。

Output

    对每组数据,输出一行一个整数,表示答案模2^31的值。

Sample Input

2
4 4 3
10 10 5

Sample Output

20
148

HINT

 

1 < =N.m < =10^5  , 1 < =Q < =2×10^4

 

Source

 

数学 容斥 莫比乌斯反演

【能同时整除i和j的所有自然数之和】也就是gcd(i,j)的所有因数的和。

设x的所有因数的和为F,则F(x)=$ \sum_{d|x}^{x}d $

迁移这里的思想 http://www.cnblogs.com/SilverNebula/p/6582843.html 可以求出一定范围内有多少数对的gcd等于特定值

不看那个链接也没关系,我打算再写一遍

,即N,M范围内gcd(i,j)==x的数对的数量

——————太长不看的一部分推导——————

(暂时懒得写)

 

————————————

则  ←此处N和M均为原N、M除以x(懒得重作图了)

 

一番变形得

 

 

后面那个sigma里的东西可以预处理出来。

如何解决题目中a的限制呢?

将询问离线,按a从小到大排序,回答每个询问时,把值小于a的F(x)都添加进来,其他的F(x)置为0。这一操作可以用树状数组维护

跑了1w+ms,之后看popoQQQ dalao的题解说这个模数可以直接自然溢出……于是删掉了所有longlong和取模,可以跑3700+ms

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #define LL long long
  9 using namespace std;
 10 const int mxn=100005;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 struct F{
 18     int pos;
 19     int v;
 20     bool operator < (F b)const{
 21         return v<b.v;
 22     }
 23 }f[mxn];
 24 int pri[mxn],mu[mxn],cnt=0;
 25 bool vis[mxn];
 26 void init(){
 27     mu[1]=1;
 28     for(int i=2;i<mxn;i++){
 29         if(!vis[i]){
 30             pri[++cnt]=i;
 31             mu[i]=-1;
 32         }
 33         for(int j=1;j<=cnt && (LL)pri[j]*i<mxn;j++){
 34             vis[pri[j]*i]=1;
 35             if(i%pri[j]==0){mu[pri[j]*i]=0;break;}
 36             mu[pri[j]*i]=-mu[i];
 37         }
 38     }
 39     for(int i=1;i<mxn;i++){//计算因数和 
 40         f[i].pos=i;
 41         for(int j=i;j<mxn;j+=i)
 42             f[j].v+=i;
 43     }
 44     sort(f+1,f+mxn);
 45     return;
 46 }
 47 //
 48 int t[mxn];
 49 int ed;
 50 void add(int x,int v){
 51     while(x<=ed){t[x]+=v;x+=x&-x;}
 52     return;
 53 }
 54 int ask(int x){
 55     int res=0;
 56     while(x){res=res+t[x];x-=x&-x;}
 57     return res&0x7fffffff;
 58 }
 59 struct que{
 60     int n,m,a;
 61     int id;
 62 }q[mxn];
 63 inline int cmp(const que x,const que y){return x.a<y.a;}
 64 int n;
 65 int ans[mxn];
 66 int calc(int a,int b){
 67     int res=0;int pos;
 68     if(a>b)swap(a,b);
 69     for(int i=1;i<=a;i=pos+1){
 70         int x=a/i,y=b/i;
 71         pos=min(a/x,b/y);
 72         res+=x*y*(ask(pos)-ask(i-1));
 73     }
 74     return res&0x7fffffff;
 75 }
 76 void solve(int x){
 77     ans[q[x].id]=calc(q[x].m,q[x].n);
 78     return;
 79 }
 80 int main(){
 81     int i,j;
 82     init();ed=mxn;
 83     n=read();
 84     for(i=1;i<=n;i++){
 85         q[i].n=read();q[i].m=read();q[i].a=read();
 86         q[i].id=i;
 87     }
 88     sort(q+1,q+n+1,cmp);
 89     int hd=1;
 90     for(i=1;i<=n;i++){
 91         while(hd<mxn && f[hd].v<=q[i].a){
 92             for(j=f[hd].pos;j<mxn;j+=f[hd].pos){
 93                 add(j,f[hd].v*mu[j/f[hd].pos]);
 94             }
 95             hd++;
 96         }
 97         solve(i);
 98     }
 99     for(i=1;i<=n;i++)
100         printf("%d\n",ans[i]&0x7fffffff);
101     return 0;
102 }
103 //&2147483647
104 /*
105 3
106 500 800 239
107 2798 2389 9023
108 1200 100000 20000
109 */

 

posted @ 2017-03-21 19:17  SilverNebula  阅读(180)  评论(0编辑  收藏  举报
AmazingCounters.com