[BZOJ3309]DZY Loves Math(莫比乌斯反演+线性筛)

$\sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum\limits_{d|T}f(d)\mu(\frac{T}{d})$

求出$g(n)=\sum_{d|T}f(d)\mu(\frac{n}{d})$的前缀和,分块加速。

考虑怎么快速求g。观察什么时候d能对答案产生贡献,显然当且仅当:对于n的每个质因子,d包含这个质因子的次幂数至多比n包含这个质因子的次幂数少1,否则n/d就会包含平方因子。

接下来分两种情况考虑(显然若n只包含一个质因子则g(n)=1):

1) n中存在两个质因子次数不同。

那么考虑所有次数的最大值,设为k。当我们确定n中次数为k的那些因子的选取情况时(这里选取是指是否d包含这个因子的次数比n少1),剩下的数若选取个数为奇数则$\mu$为-1否则为1。考虑到组合数的性质,n个数中选取奇数个的方案数与选取偶数个相同,所以这种情况整个的贡献为0。

2) n中所有质因子次数相同

与上面不同的是,这里已经不存在次数小于k的因子了。那么,这些质因子的选取情况与$\mu$的乘积同样由于上面那个组合数的性质,使和为0。但有一个数不同,就是当d包含的所有因子的次数都比n少1时,f(d)为k-1而不是k。综上这部分的g(n)=(-1)^(质因子个数+1)。

考虑线性筛求g。分别记录每个数最小因子的次数,最小因子的乘积,转移显然。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 typedef long long ll;
 5 using namespace std;
 6 
 7 const int N=10000010;
 8 int T,n,m,tot,b[N],p[N];
 9 ll g[N],f[N],h[N];
10 
11 void init(int n){
12     rep(i,2,n){
13         if (!b[i]) p[++tot]=i,h[i]=1,f[i]=i,g[i]=1;
14         for (int j=1; j<=tot && p[j]*i<=n; j++){
15             int t=p[j]*i; b[t]=1;
16             if (i%p[j]==0){
17                 h[t]=h[i]+1; f[t]=f[i]*p[j];
18                 int s=t/f[t];
19                 if (s==1) g[t]=1; else g[t]=(h[s]==h[t]) ? -g[s] : 0;
20             }else h[t]=1,f[t]=p[j],g[t]=(h[i]==1) ? -g[i] : 0;
21         }
22     }
23     rep(i,1,n) g[i]+=g[i-1];
24 }
25 
26 ll solve(){
27     if (n>m) swap(n,m); ll res=0;
28     for (int i=1,lst; i<=n; i=lst+1)
29         lst=min(n/(n/i),m/(m/i)),res+=1ll*(n/i)*(m/i)*(g[lst]-g[i-1]);
30     return res;
31 }
32 
33 int main(){
34     freopen("bzoj3309.in","r",stdin);
35     freopen("bzoj3309.out","w",stdout);
36     init(10000000);
37     for (scanf("%d",&T); T--; )
38         scanf("%d%d",&n,&m),printf("%lld\n",solve());
39     return 0;
40 }

 

posted @ 2019-01-18 18:42  HocRiser  阅读(203)  评论(0编辑  收藏  举报