B3801 [NICA #1] 乘只因 题解

· · 题解

注意到题目中有一个很重要的性质:

\prod\limits_{i=1}^na_i=\mathrm{lcm}\{a_1,a_2,\ldots,a_n\}

易证 a_i 之间两两互质,即 \forall 1\le i<j\le n,\gcd(a_i,a_j)=1,所以如果 n 的唯一分解中包含的某个质数有多个,只能放在同一个 a_i 里。于是我们只需统计 n 的唯一分解中包含的质数种类数 c

问题转化一下,就是如下的形式:

显然是第二类斯特林数,套递推公式直接计算即可。第二类斯特林数递推公式如下: $$\begin{Bmatrix}n\\m\end{Bmatrix}=\begin{Bmatrix}n-1\\m-1\end{Bmatrix}+m\begin{Bmatrix}n-1\\m\end{Bmatrix}$$ 边界条件为 $\begin{Bmatrix}n\\0\end{Bmatrix}=[n=0]$。这里 $[]$ 指艾弗森括号。 放代码: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; bitset<10000001> b; vector<int> p; int f(int n,int m){ vector<vector<int> > s(n+1,vector<int>(m+1)); for(int i=0;i<=n;i++)s[i][0]=!i; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) s[i][j]=s[i-1][j-1]+j*s[i-1][j]; return s[n][m]; } // 计算第二类斯特林数 main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); for(int i=2;i<1e7;i++){ if(!b[i])p.emplace_back(i); for(int j:p){ if(i*j>1e7)break; b[i*j]=true; if(!(i%j))break; } } // 线性筛 int t; cin>>t; while(t--){ int n,k,c=0; cin>>n>>k; for(int i:p){ if(i*i>n)break; if(!(n%i))c++; while(!(n%i))n/=i; } // 统计质数种类数 if(n>1)c++; if(k>c)cout<<"0\n"; // 特判 else cout<<f(c,k)<<'\n'; } return 0; } ```