《怪物獵人崛起》軍官樣式防具幻化分享
阿新 • • 發佈:2021-06-10
原題連結
考察:莫比烏斯反演
菜狗不會啊QAQ
思路:
參考了大佬的題解,我們列出求答案的式子.
注意:f[k]為k的質因子個數.
\[\sum_{k=1}^{min(n,m)}[f[k]<=p]\sum_{i=1}^{min(n/k,m/k)}mob[i]*\frac{n}{i*k}*\frac{m}{i*k} \]這就是列舉\(k\),求\(gcd(x,y)==k\)的對數.直接這麼算一定TLE.所以進一步化簡式子.
令\(T = i*k\)
這就是列舉T,再列舉T的因數,如果滿足\(f[k]<=p\),對於T 1~min(n,m) k 1~T 累加\(mob\)和
但是我們可以先列舉k,再列舉k的倍數,這樣就可以優化時間複雜度.而且後半部分可以預處理,列舉k,T後,k的質因子個數也就確定了,那麼我們可以求出\(sum[T][f[k]]+=mob[T/k]\)
最後把T,k累加即可.
Code
#include <iostream> #include <cstring> using namespace std; typedef long long LL; const int N = 500010,M=20; int prime[N],cnt,mob[N],n,m,P,f[N],sum[N][M]; bool st[N]; void GetPrime(int n) { mob[1] = 1; for(int i=2;i<=n;i++) { if(!st[i]) prime[++cnt] = i,mob[i] = -1; for(int j=1;prime[j]<=n/i;j++) { st[i*prime[j]] = 1; if(i%prime[j]==0) { mob[i*prime[j]] = 0; break; } mob[i*prime[j]] = mob[i]*(-1); } } } void init(int n) { int t = n; for(int i=1;prime[i]<=t/prime[i];i++) { if(t%prime[i]==0) { int s = 0; while(t%prime[i]==0) t/=prime[i],s++; f[n]+=s; } } if(t>1) f[n]++; } int main() { int T; scanf("%d",&T); GetPrime(N-1); for(int i=1;i<=N-10;i++) init(i); for(int i=1;i<=N-10;i++) for(int j=i;j<=N-10;j+=i) sum[j][f[i]]+=mob[j/i]; for(int i=1;i<=N-10;i++) for(int j=0;j<M;j++)//f[g]<=j的和 if(j) sum[i][j] += sum[i][j-1];//不能一起加,因為會重複. for(int i=1;i<=N-10;i++) for(int j=0;j<M;j++)//f[g]<=j的和 sum[i][j] += sum[i-1][j]; while(T--) { scanf("%d%d%d",&n,&m,&P); if(P>=M) {printf("%lld\n",(LL)n*m);continue;} if(n>m) swap(n,m); LL res = 0; for(int i=1,r;i<=n;i=r+1) { r = min(n/(n/i),m/(m/i)); res+=(LL)(sum[r][P]-sum[i-1][P])*(n/i)*(m/i); } printf("%lld\n",res); } return 0; }