题意
bzoj3529
就是求
(
)
题解
先不去考虑a这个限制
那么就等于
而 都是可以预处理求出来的
然后再去考虑a这个限制,可以发现每个格子里面的结果就是对应的
,因此只要
就可以了
因此用树状数组维护
我不会说…我改了很久…是因为….100000写成了10000【再见再见再见】
当时以为是ll的错【再见再见再见】
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010
int mu[N],sig[N],prime[N],n,tot=0,ms[N],tree[N],ans[N];
bool notprime[N];
struct node{int x,y,a,num;}q[N];
struct node1{int sig,num;}f[N];
bool cmp(node x,node y){return x.a<y.a;}
bool cmp1(node1 x,node1 y){return x.sig<y.sig;}
void mobius(){
mu[1]=1;sig[1]=1;ms[1]=1;
memset(notprime,false,sizeof(notprime));notprime[1]=true;
for(int i=2;i<=100000;i++){
if(!notprime[i]) prime[++tot]=i,mu[i]=-1,sig[i]=i+1,ms[i]=i;
for(int j=1;j<=tot,prime[j]*i<=100000;j++){
notprime[i*prime[j]]=true;
if(i%prime[j]==0){
ms[prime[j]*i]=ms[i]*prime[j];mu[prime[j]*i]=0;
if(ms[i]==i) sig[i*prime[j]]=(i*prime[j]*prime[j]-1)/(prime[j]-1);
else sig[i*prime[j]]=sig[i/ms[i]]*sig[prime[j]*ms[i]];
break;
}mu[i*prime[j]]=-mu[i];sig[i*prime[j]]=sig[i]*sig[prime[j]];ms[i*prime[j]]=prime[j];
}
}
}
void add(int x,int y){
for(int i=x;i<=100000;i+=i&-i) tree[i]+=y;
}
int query(int x){
int sum=0;
for(int i=x;i;i-=i&-i) sum+=tree[i];
return sum;
}
void change(int &now,int a){
while(now<=100000 && a>=f[now].sig){
for(int j=1;f[now].num*j<=100000;j++)
add(f[now].num*j,f[now].sig*mu[j]);
now++;
}
}
int solve(int x,int y){
int res=0;if(x>y) swap(x,y);
for(int j=1,last=0;j<=x;j=last+1){
last=min(x/(x/j),y/(y/j));
res+=(query(last)-query(j-1))*(x/j)*(y/j);
}return res&0x7fffffff;
}
int main(){
scanf("%d",&n);mobius();
for(int i=1;i<=100000;i++) f[i].sig=sig[i],f[i].num=i;
sort(f+1,f+100000+1,cmp1);
for(int i=1;i<=n;i++) scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].a),q[i].num=i;
sort(q+1,q+n+1,cmp);
for(int i=1,now=1;i<=n;i++){
change(now,q[i].a);
ans[q[i].num]=solve(q[i].x,q[i].y);
}for(int i=1;i<=n;i++) printf("%d\n",ans[i]&0x7fffffff);
return 0;
}