【SDOI2014】數表(table)

Description

這裏寫圖片描述
這裏寫圖片描述

Solution

很明顯可以發現,n和m交換是不會影響答案的,
我們可以先設一個f(x)=d|xd 表示i 的約數和,還有一個數組g(x)=ni=1mj=1(gcd(i,j)=x) ,而答案明顯就是ni=1f(i)g(i) ,看到了g(x) 中的gcd 可以很快能夠想到莫比烏斯反演,對g(x) 我們化簡一下:
g(x)=nii=1mjj=1d=gcd(i,j)μ(d)
=x|dμ(d)ndmd
然後把化簡後的g(x) 代入求答案得:
ans=ni=1f(i)x|dμ(d)ndmd
=nd=1ndmdi|df(i)μ(di)
我們令h(i)=i|df(i)μ(di) ,因爲只有當f(x)a 的時候纔有貢獻,所以,把所有詢問按照a 從小到大離線排序,然後把符合條件的f(x) 一個個加入進去,而對於h(i) 我們可以用前綴和來維護。

Code

#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<stdio.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=1e5+5;
typedef long long ll;
struct arr{
    int n,m,mx,bh;
}a[20005];
struct da{
    int f,pr;
}f[maxn];
bool cmp(arr x,arr y){return x.mx<y.mx;}
bool cmp1(da x,da y){return x.f<y.f;}
bool p[maxn];
int cas,n,m,i,j,k,mx,s[maxn],mu[maxn],t[maxn];
ll mo,ans[maxn];
void screen(int mx){
    int i,j,k;
    fo(i,2,mx){
        if(!p[i]) s[++s[0]]=i,mu[i]=-1;
        fo(j,1,s[0]){
            k=i*s[j];
            if(k>mx) break;
            p[k]=true;
            if(i%s[j]==0){
                mu[k]=0;
                break;
            }
            mu[k]=mu[i]*mu[s[j]];
        }
    }
    mu[1]=1;
    fo(i,1,mx){
        f[i].pr=i;
        for(j=i;j<=mx;j+=i) f[j].f+=i;
    }
}
void add(int x,int sum){
    for(x=x;x<=mx;x+=x&(-x)) t[x]+=sum;
}
int get(int x){
    int sum;
    sum=0;if(x==0) return 0;
    for(x=x;x;x-=x&(-x)) sum+=t[x];
    return sum;
}
void solve(int x)
{
    int n,m,bh,i,j;
    n=a[x].n,m=a[x].m,bh=a[x].bh;
    for(i=1;i<=n;i=j+1){
        j=min(n/(n/i),m/(m/i));
        ans[bh]+=(n/i)*(m/i)*(get(j)-get(i-1));
    }
}
int main(){
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);
    mo=1;fo(i,1,31) mo=mo*2;
    scanf("%d",&cas);
    fo(i,1,cas){
        scanf("%d%d%d",&a[i].n,&a[i].m,&a[i].mx);
        if(a[i].n>a[i].m) swap(a[i].n,a[i].m);
        a[i].bh=i;mx=max(mx,a[i].n);
    }
    screen(mx);
    sort(a+1,a+cas+1,cmp);
    sort(f+1,f+mx+1,cmp1);
    j=0;
    fo(i,1,cas){
        while(j<mx&&f[j+1].f<=a[i].mx){
            j++;    
            for(k=f[j].pr;k<=mx;k+=f[j].pr){
                add(k,f[j].f*mu[k/f[j].pr]);
            }
        }
        solve(i);
    }
    fo(i,1,cas) printf("%lld\n",ans[i]%mo);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章