数学(数论)BZOJ 3309: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
4
10000
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
10000
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
Sample Output
35793453939901
14225956593420
4332838845846
15400094813
14225956593420
4332838845846
15400094813
HINT
【数据规模】
T<=10000
1<=a,b<=10^7
莫比乌斯反演得到:
(盗图)
然后有类似于yy的GCD的做法,分块加速,复杂度变O(√n)
问题就是如何快速预处理出后面的式子,设其为g(x),这时研究g函数性质,g(x)的取值有哪些规律呢?
将x分解质因数,x=p1a1*p2a2*p3a3*……*pnan,函数即是将x分解成两个集合,求值再求和。
1.假设a不全是同一个值,那么那个较小的素数,可以对每个情况属于两个集合使得其值互为相反数,所以值为0。
2.a值全相等时,易得g(x)=(-1)a-1,根据欧拉线性筛的性质,每个数被最小的素因子枚举到,可以维护两个值,当前的a值,去掉当前最小的素因子后的数。
然后就可以
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int N=10000010; 6 int g[N],nxt[N],mem[N]; 7 int prime[N],cnt; 8 bool check[N]; 9 10 void Prepare(){ 11 for(int i=2;i<N;i++){ 12 if(!check[i]){ 13 prime[++cnt]=i; 14 g[i]=nxt[i]=mem[i]=1; 15 } 16 for(int j=1;j<=cnt;j++){ 17 if(i*prime[j]>=N)break; 18 check[i*prime[j]]=true; 19 if(i%prime[j]==0){ 20 nxt[i*prime[j]]=nxt[i]; 21 mem[i*prime[j]]=mem[i]+1; 22 if(nxt[i]==1)g[i*prime[j]]=1; 23 else if(mem[nxt[i]]==mem[i]+1) 24 g[i*prime[j]]=-g[nxt[i]]; 25 else g[i*prime[j]]=0; 26 break; 27 } 28 else{ 29 nxt[i*prime[j]]=i; 30 mem[i*prime[j]]=1; 31 g[i*prime[j]]=(mem[i]==1)?-g[i]:0; 32 } 33 } 34 } 35 for(int i=1;i<N;i++) 36 g[i]+=g[i-1]; 37 } 38 int T,a,b; 39 long long ans; 40 int main(){ 41 Prepare(); 42 scanf("%d",&T); 43 while(T--){ 44 scanf("%d%d",&a,&b); 45 if(a>b)swap(a,b);ans=0; 46 for(int i=1,p=1;i<=a;i=p+1){ 47 p=min(a/(a/i),b/(b/i)); 48 ans+=1ll*(g[p]-g[i-1])*(a/i)*(b/i); 49 } 50 printf("%lld\n",ans); 51 } 52 return 0; 53 }
维护了。
尽最大的努力,做最好的自己!