[bzoj3309] DZY Loves Math

Description

對於正整數n,定義f(n)爲n所含質因子的最大冪指數。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
給定正整數a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b)。html

Input

第一行一個數T,表示詢問數。
接下來T行,每行兩個數a,b,表示一個詢問。c++

Output

對於每個詢問,輸出一行一個非負整數做爲回答。git

Sample Input

4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957

Sample Output

35793453939901
14225956593420
4332838845846
15400094813

HINT

【數據規模】spa

T<=10000code

1<=a,b<=10^7htm

solution

前置知識:莫比烏斯反演blog

題目讓求的是:
\[ ans=\sum_{i=1}^n\sum _{j=1}^mf(gcd(i,j)) \]
而後經過莫比烏斯反演能夠獲得:
\[ ans=\sum_{T=1}^{min(n,m)}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}f(d)\mu(\frac{T}{d}) \]
而後令式子後面一塊爲\(g\),即:
\[ g(T)=\sum_{d|T}f(d)\mu(\frac{T}{d}) \]
顯然這種題不線篩出這個東西不讓過,ip

而後分解下\(d\)\(T\)
\[ T=\prod_{i=1}^ka_i^{p_i},d=\prod_{i=1}^ka_i^{x_i} \]
考慮\(\mu(\frac{T}{d})\),顯然對於任意\(i\),知足\(x_i=p_i\)或者\(x_i=p_i-1\),不然\(\mu\)爲0。get

\(res=f(T)\),有\(num\)\(p_i\)等於\(res\),而後分類討論:input

\(num=k\),則\(f(d)=res\)的答案爲:
\[ \begin{align} &\sum_{f(d)=res}f(d)\mu(\frac{T}{d})\\ =&res*\sum_{f(d)=res}\mu(\frac{T}{d})\\ =&res*\sum_{i=1}^k(-1)^{k-i}\binom{k}{i}\\ =&res*(1+(-1))^k-res*(-1)^k\\ =&res*(-1)^{k+1} \end{align} \]
\(f(d)=res-1\)的答案爲:
\[ \begin{align} &\sum_{f(d)=res-1}f(d)\mu(\frac{T}{d})=(res-1)*(-1)^k \end{align} \]
綜合起來,答案爲\(res*(-1)^{k+1}+(res-1)*(-1)^k=(-1)^{k+1}\)

不然,即\(num\neq f(T)\),則\(f(d)=res\)的答案爲:
\[ \begin{align} &\sum_{f(d)=res}f(d)\mu(\frac{T}{d})\\ =&res*\sum_{i=1}^{num}(-1)^{k-i}\binom{num}{i}*\sum_{i=0}^{k-num}(-1)^i\binom{k-num}{i}\\ =&res*\sum_{i=1}^{num}(-1)^{k-i}\binom{num}{i}*0=0 \end{align} \]
同理\(f(d)=res-1\)的答案也爲0,因此綜合起來答案爲0。

因爲線篩的時候每一個數是被最小的質因子篩掉的,因此考慮線篩的時候對於每一個數最小質因子出現了多少次,以及不算這個質因子剩下的是多少,而後對於\(g\)討論下就好了。

剩下的隨便數論分塊下就作完了,時間複雜度\(O(n+q\sqrt{n})\)

#include<bits/stdc++.h>
using namespace std;

#define ll long long 

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) x=-x,putchar('-');
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1e7+1;

int f[maxn],pri[maxn/20],tot,num[maxn],lst[maxn];
bool vis[maxn];

void sieve() {
    for(int i=2;i<maxn;i++) {
        if(!vis[i]) pri[++tot]=i,f[i]=num[i]=lst[i]=1;
        for(int j=1;j<=tot&&i*pri[j]<maxn;j++) {
            vis[i*pri[j]]=1;
            if(!(i%pri[j])) {
                lst[i*pri[j]]=lst[i];
                num[i*pri[j]]=num[i]+1;
                if(lst[i*pri[j]]==1) f[i*pri[j]]=1;
                else f[i*pri[j]]=(num[lst[i*pri[j]]]==num[i*pri[j]]?-f[lst[i]]:0);
                break;
            }
            lst[i*pri[j]]=i;
            num[i*pri[j]]=1;
            f[i*pri[j]]=(num[i]==1?-f[i]:0);
        }
    }
    //for(int i=1;i<=30;i++) printf("%d %d %d %d\n",i,f[i],lst[i],num[i]);;
    for(int i=1;i<maxn;i++) f[i]=f[i-1]+f[i];
    //for(int i=1;i<=20;i++) write(f[i]);
}

signed main() {
    int t;read(t);
    //int PRE=clock();
    sieve();
    //cerr << (double)(clock()-PRE)/CLOCKS_PER_SEC << endl;
    while(t--) {
        int n,m;read(n),read(m);
        int T=1;ll ans=0;
        while(T<=n&&T<=m) {
            int pre=T;T=min(n/(n/T),m/(m/T));
            ans+=1ll*(n/T)*(m/T)*(f[T]-f[pre-1]);T++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索