bzoj3529: [Sdoi2014]数表 (莫比乌斯反演)

题意

bzoj3529
就是求 i = 1 n j = 1 m σ ( g c d ( i , j ) ) σ ( g c d ( i , j ) <= a


题解

先不去考虑a这个限制
那么就等于

= i = 1 n j = 1 m d | g c d ( i , j ) d = d = 1 n σ ( d ) i = 1 n j = 1 m g c d ( i , j ) == d = d = 1 n σ ( d ) i = 1 n d j = 1 m d g c d ( i , j ) == 1 = d = 1 n σ ( d ) i = 1 n d j = 1 m d ϵ ( g c d ( i , j ) ) = d = 1 n σ ( d ) k = 1 n d μ ( k ) n k d m k d

σ μ 都是可以预处理求出来的

然后再去考虑a这个限制,可以发现每个格子里面的结果就是对应的 σ ( g c d ( i , j ) ) ,因此只要 σ 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;
} 

猜你喜欢

转载自blog.csdn.net/sunshiness_s/article/details/80322523