3529: [Sdoi2014]数表
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
【分析】
先假设没有a的限制。。
设g(i)=ΣΣ[(x,y)==i](1<=x<=n,1<==y<=m)
g(i)=Σmu[d]*(n/(i*d))*(m/(i*d))
尝试把i和d分开,设D=i*d
那么g(i)=(n/D)*(M/D)*Σmu[i/D] (i|D)
设f(i)为i的约数和,这个可以nlogn求出来,那么ans=g(i)*f(i)=(n/D)*(M/D)*Σmu[i/D]*f(i) (i|D)
对于a的限制,是说f(i)<=a的东西对ans有贡献,其他的没有贡献。
所以就离线一下~~按照f(i)排序,询问按照a排序,因为要询问前缀和,所以当他开始有贡献的时候就把他放到树状数组里面去。
剩下的就是分块处理了。
Mod的地要自然溢出最后取模?不然会超时,像我一样~
别人的题解:
![](https://images2015.cnblogs.com/blog/431969/201607/431969-20160721101847216-513785198.png)
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 100010 10 #define LL unsigned int 11 #define INF 0xfffffff 12 LL mx; 13 LL Mod; 14 15 int mu[Maxn]; 16 LL pri[Maxn],pl; 17 bool q[Maxn]; 18 19 20 struct node 21 { 22 LL x,y,a,ans,id; 23 }t[Maxn],f[Maxn]; 24 25 LL mymin(LL x,LL y) {return x<y?x:y;} 26 LL mymax(LL x,LL y) {return x>y?x:y;} 27 28 bool cmp(node x,node y) {return x.a<y.a;} 29 bool cmp2(node x,node y) {return x.id<y.id;} 30 31 void get_mu() 32 { 33 pl=0; 34 memset(q,1,sizeof(q)); 35 mu[1]=1; 36 for(LL i=2;i<=mx;i++) 37 { 38 if(q[i]) 39 { 40 pri[++pl]=i; 41 mu[i]=-1; 42 } 43 for(LL j=1;j<=pl;j++) 44 { 45 if(i*pri[j]>mx) break; 46 q[i*pri[j]]=0; 47 if(i%pri[j]==0) mu[i*pri[j]]=0; 48 else mu[i*pri[j]]=-mu[i]; 49 if(i%pri[j]==0) break; 50 } 51 } 52 for(LL i=1;i<=mx;i++) f[i].a=0; 53 for(LL i=1;i<=mx;i++) 54 for(LL j=i;j<=mx;j+=i) 55 f[j].a=f[j].a+i; 56 for(LL i=1;i<=mx;i++) f[i].id=i; 57 } 58 59 LL c[Maxn],as[Maxn]; 60 61 LL add(LL x,LL y) 62 { 63 as[x]+=y; 64 for(LL i=x;i<=mx;i+=i&(-i)) 65 c[i]+=y; 66 } 67 68 LL get_sum(LL x) 69 { 70 LL ans=0; 71 for(LL i=x;i>=1;i-=i&(-i)) 72 ans+=c[i]; 73 return ans; 74 } 75 76 void change(LL x) 77 { 78 LL now=f[x].id; 79 for(LL i=now;i<=mx;i+=now) 80 add(i,(LL)(mu[i/now]*f[x].a)); 81 } 82 83 84 LL get_ans(LL n,LL m) 85 { 86 LL ans=0,t; 87 if(n>m) t=n,n=m,m=t; 88 89 LL sq=(LL)ceil(sqrt((double)m)); 90 for(LL i=1;i<=mymin(sq,n);i++) 91 { 92 LL x=(LL)(n/i),y=(LL)(m/i); 93 ans+=as[i]*(n/i)*(m/i); 94 } 95 96 97 for(LL i=sq+1;i<=n;) 98 { 99 LL x=n/i,y=m/i; 100 LL r1=n/x+1,r2=m/y+1; 101 if(r1>n+1) r1=n+1; 102 if(r2>n+1) r2=n+1; 103 LL r=mymin(r1,r2); 104 105 ans+=(get_sum(r-1)-get_sum(i-1))*x*y; 106 i=r; 107 } 108 109 return ans; 110 } 111 112 int main() 113 { 114 Mod=1; 115 for(LL i=1;i<=31;i++) Mod*=2; 116 117 LL T; 118 T=1; 119 scanf("%d",&T); 120 121 mx=0; 122 123 for(LL i=1;i<=T;i++) 124 { 125 scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].a); 126 mx=mymax(mx,mymin(t[i].x,t[i].y)); 127 t[i].id=i; 128 } 129 sort(t+1,t+1+T,cmp); 130 get_mu(); 131 sort(f+1,f+1+mx,cmp); 132 133 memset(c,0,sizeof(c)); 134 memset(as,0,sizeof(as)); 135 LL now=1; 136 for(LL i=1;i<=T;i++) 137 { 138 while(f[now].a<=t[i].a&&now<=mx) change(now),now++; 139 t[i].ans=get_ans(t[i].x,t[i].y); 140 } 141 sort(t+1,t+1+T,cmp2); 142 143 for(LL i=1;i<=T;i++) 144 { 145 printf("%d ",(t[i].ans%Mod+Mod)%Mod); 146 } 147 return 0; 148 }
2016-09-03 10:57:57