BZOJ 3529[SDOI2014]数表
题面:
3529: [Sdoi2014]数表
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1908 Solved: 969
[Submit][Status][Discuss]
Description
有一张N×m的数表,其第i行第j列(1 < =i < =n,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
4 4 3
10 10 5
Sample Output
20
148
148
HINT
1 < =N.m < =10^5 , 1 < =Q < =2×10^4
题目要求
$\sum_{i=1}^{n}\sum_{j=1}^{m}\sigma(gcd(i,j))$
$=\sum_{d=1}^{min(n,m)}\sigma(d)\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=d]$
$=\sum_{T=1}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(\frac{T}{d})\sigma(d)$
令$g[T]=\sum_{d|T}\mu(\frac{T}{d})\sigma(d)$
法一:
线性筛求出$g[T]$,$O(n)$。
法二:
枚举$d$,更新$d$倍数的$g$,$O(nlogn)$。
但是有$a$的限制,只能用法二。
将$\sigma(i)$由小到大排序,将询问按$a$由小到大排序,离线回答询问。
每次将小于等于$a_{i}$的$f[T]$加入树状数组,分块回答询问。
时间复杂度$O(nlog^{2}n+T\sqrt nlogn)$。
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 100000 6 #define lowbit(x) x&(-x) 7 #define INF 2147483647 8 struct node 9 { 10 int x;int y; 11 }id[maxn+1]; 12 bool cmp(const node &a,const node &b) 13 { 14 return a.x<b.x; 15 } 16 int p[maxn+1]; 17 int cnt,mu[maxn+1]; 18 bool book[maxn+1]; 19 void init() 20 { 21 mu[1]=1; 22 id[1]=(node){1,1}; 23 for(int i=2;i<=maxn;i++) 24 { 25 if(!book[i]) 26 { 27 p[++cnt]=i; 28 id[i]=(node){i+1,i}; 29 mu[i]=-1; 30 } 31 for(int j=1;j<=cnt&&i*p[j]<=maxn;j++) 32 { 33 book[i*p[j]]=true; 34 if(i%p[j]!=0) 35 { 36 mu[i*p[j]]=-mu[i]; 37 id[i*p[j]]=(node){id[i].x*id[p[j]].x,i*p[j]}; 38 } 39 else 40 { 41 id[i*p[j]]=(node){id[i].x+(id[i].x-id[i/p[j]].x)*p[j],i*p[j]}; 42 break; 43 } 44 } 45 } 46 } 47 int T; 48 struct QAQ 49 { 50 int n,m,w,dfn; 51 }QWQ[20002]; 52 bool cmp1(const QAQ&a,const QAQ&b) 53 { 54 return a.w<b.w; 55 } 56 #define maxm 404000 57 int c[maxm+1],ans[20002]; 58 void update(int x,int w) 59 { 60 for(;x<=maxm;x+=lowbit(x)) 61 c[x]+=w; 62 } 63 int query(int x) 64 { 65 int ans=0; 66 for(;x>0;x-=lowbit(x)) 67 ans+=c[x]; 68 return ans; 69 } 70 int qaq(int n,int m) 71 { 72 int last=0; 73 int sum=0; 74 if(n>m) 75 swap(n,m); 76 for(int i=1;i<=n;i=last+1) 77 { 78 last=min(n/(n/i),m/(m/i)); 79 sum+=(n/i)*(m/i)*(query(last)-query(i-1)); 80 } 81 return sum; 82 } 83 void pushup(int i) 84 { 85 for(int j=1;id[i].y*j<=maxm;j++) 86 update(j*id[i].y,id[i].x*mu[j]); 87 } 88 void work() 89 { 90 int tmp=0; 91 for(int i=1;i<=T;i++) 92 { 93 while(tmp+1<=maxn&&id[tmp+1].x<=QWQ[i].w) 94 pushup(++tmp); 95 ans[QWQ[i].dfn]=qaq(QWQ[i].n,QWQ[i].m); 96 } 97 } 98 int main() 99 { 100 init(); 101 scanf("%d",&T); 102 for(int i=1;i<=T;i++) 103 { 104 scanf("%d%d%d",&QWQ[i].n,&QWQ[i].m,&QWQ[i].w); 105 QWQ[i].dfn=i; 106 } 107 sort(id+1,id+maxn+1,cmp); 108 sort(QWQ+1,QWQ+T+1,cmp1); 109 work(); 110 for(int i=1;i<=T;i++) 111 printf("%d\n",(ans[i]&INF)); 112 }