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)。
Input
第一行一个数T,表示询问数。
接下来T行,每行两个数a,b,表示一个询问。
Output
对于每一个询问,输出一行一个非负整数作为回答。
Sample Input
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
Sample Output
14225956593420
4332838845846
15400094813
HINT
【数据规模】
T<=10000
1<=a,b<=10^7
题解Here!
$$Ans=\sum_{D=1}^n\lfloor\frac{n}{D}\rfloor\lfloor\frac{m}{D}\rfloor\sum_{d|D}\mu(\frac{D}{d})f(d)$$
首先设$D=\prod_{i=1}^kp_i^{x_i},d=\prod_{i=1}^kp_i^{y_i}$。
要使$\mu(\frac{D}{d})!=0$,必须满足$y_i=x_i$或者$y_i=x_{i−1}$。
令$a=\max_{i=1}^kx_i$,则$f(d)=a\text{或}a-1$。
假设$D$中一共有$q$个质因子的指数为$a$。
1. $q==k$:
- $f(d)=a$:
$$\sum_{f(d)=a}\mu(\frac{D}{d})f(d)=a\times\sum_{f(d)=a}\mu(\frac{D}{d})=a\times\sum_{i=1}^k(-1)^{k-i}C_k^i=a\times (-1)^{k+1}$$
- $f(d)=a−1$:
$$\sum_{f(d)=a-1}f(d)\mu(\frac{D}{d})=(a-1)\times\sum_{f(d)=a-1}\mu(\frac{D}{d})=(a-1)\times(-1)^k$$
所以当$q==k$时,$$F(D)=a\times(-1)^k+1+(a-1)\times(-1)^k=(-1)^k+1$$
2. $q<k$:
- $f(d)=a$:
$$\sum_{f(d)=a}f(d)\mu(\frac{D}{d})=a\times\sum_{f(d)=a}\mu(\frac{D}{d})=a\times\sum_{i=1}^q(-1)^{q-i}C_q^i\times\sum_{j=0}^{k-q}(-1)^jC_{k-q}^j=0$$
- $f(d)=a−1$:
$$\sum_{f(d)=a-1}f(d)\mu(\frac{D}{d})=(a-1)\times\sum_{f(d)=a-1}\mu(\frac{D}{d})=(a-1)\times(-1)^q\times\sum_{j=0}^{k-q}(-1)^jC_{k-q}^j=0$$
所以当$q<k$时,$F(D)=0$。
知道这些,我们可以线筛的时候记录一下最小质因子出现的次数和除去最小质因子$p_i^{x_i}$后的数,然后判断幂指数是否相等。
所以把线性筛魔改下就好辣!
复杂度是$O(N+T\sqrt n)$。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 10000010 using namespace std; int k=0,prime[MAXN],t[MAXN],last[MAXN]; long long sum[MAXN]; bool np[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void make(){ int m=MAXN-10; for(int i=2;i<=m;i++){ if(!np[i]){ prime[++k]=i; last[i]=t[i]=1; sum[i]=1; } for(int j=1;j<=k&&prime[j]*i<=m;j++){ int x=prime[j]*i; np[x]=true; if(i%prime[j]==0){ last[x]=last[i]; t[x]=t[i]+1; if(last[x]==1)sum[x]=1; else sum[x]=(t[last[x]]==t[x]?-sum[last[x]]:0); break; } last[x]=i; t[x]=1; sum[x]=(t[i]==1?-sum[i]:0); } } for(int i=1;i<=m;i++)sum[i]+=sum[i-1]; } long long solve(int n,int m){ long long ans=0; if(n>m)swap(n,m); for(int i=1,last=1;i<=n;i=last+1){ last=min(n/(n/i),m/(m/i)); ans+=1LL*(sum[last]-sum[i-1])*(n/i)*(m/i); } return ans; } int main(){ make(); int t=read(); while(t--){ int n=read(),m=read(); printf("%lld\n",solve(n,m)); } return 0; }