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)。T<=1e4; a,b<=1e7。
Solution
一開始沒仔細看數據范圍然后打了一個每個詢問O(n)的,當然T了
(盜一張圖)
一開始我按照第二行的做的,里層外層循環都和ab有關,每一層都要sqrt(n)
然后發現f(d)和ab無關,於是把f放到里面,把和ab有關的拎出來,就變成了第三行的式子
這樣里面一層循環與ab無關,可以預處理好
我們要求的就是后面sigma的前綴和
不難想到nlogn的預處理,但這題比較卡還是T
於是要這么做
設g(T)=Σ[d|T]f(d)μ(T/d)
大力分析
將T質因數分解,對於每一個p^a,T/d的p系數要么為0要么為1,否則μ(T/d)一定為0不考慮
如果存在ai!=aj,關於T的因數p按a可以分為兩個集合,a最大A集合和a非最大的B集合
f取值由A集合的選取決定
μ由選取的總個數決定
無論A怎么選,在B中選取的奇偶方案數相同,於是總貢獻一定為0
也就是如果存在ai!=aj, g(T)=0
那么a都相等的情況
選奇數選偶數方案相同貢獻也為0
但如果p全部都選那么f的貢獻為a-1(其余選法f貢獻都為a)
所以要多減一個1,考慮μ的影響,對於有k個p的T,g(T)=(-1)^(k+1)
具體的計算方法在線性篩的時候記錄一個當前最小素數的次數和去掉最小素數后上一個數
如果清楚線性篩的原理那么還是很好想的
預處理復雜度同線性篩,詢問復雜度為sqrt(n)
Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int maxn=1e7+5; 7 8 bool flag[maxn]; int prime[maxn],cnt; 9 int t[maxn],last[maxn],g[maxn]; 10 int n,m; 11 12 void getmu(){ 13 for(int i=2;i<=1e7;i++){ 14 if(!flag[i]){ 15 prime[++cnt]=i; 16 last[i]=t[i]=1; 17 g[i]=1; 18 } 19 for(int j=1;i*prime[j]<=1e7&&j<=cnt;j++){ 20 int x=i*prime[j]; 21 flag[x]=1; 22 if(i%prime[j]==0){ 23 last[x]=last[i]; 24 t[x]=t[i]+1; 25 if(last[x]==1) 26 g[x]=1; 27 else 28 g[x]=(t[last[x]]==t[x]?-g[last[x]]:0); 29 break; 30 } 31 last[x]=i; 32 t[x]=1; 33 g[x]=(t[i]==1?-g[i]:0); 34 } 35 } 36 for(int i=1;i<=1e7;i++) 37 g[i]+=g[i-1]; 38 } 39 40 ll f(int x,int y){ 41 ll ret=0; 42 for(int i=1,pos=1;i<=x;i=pos+1){ 43 pos=min(x/(x/i),y/(y/i)); 44 ret+=1ll*(g[pos]-g[i-1])*(x/i)*(y/i); 45 } 46 return ret; 47 } 48 49 int main(){ 50 getmu(); 51 52 int T; 53 scanf("%d",&T); 54 while(T--){ 55 scanf("%d%d",&n,&m); 56 if(n>m) swap(n,m); 57 printf("%lld\n",f(n,m)); 58 } 59 return 0; 60 }