一道综合数学题
阿狸有一个可重集合\(A\),\(A\)中有\(n\)个元素,因此\(A\)有\(2n\)个子集。对于每个\(A\)的子集\(x\),定义\(f(x)\)的值为,使\(x\)的所有元素都相同的最少操作步数。操作有两种:
-
选择\(x\)中的一个元素,把这个数乘上某个质数\(p\)。
-
选择\(x\)中的一个元素,把这个数除掉某个质数\(p\)。这个数必须是\(p\)的倍数。
阿狸想知道\(\sum\limits_{x\subset A}f(x)\)的值,但是由于这个值可能很大,你只要告诉萌萌的阿狸这个数对\(1,000,000,007(10^9+7)\)取模的值。
前置知识
上指标求和公式
\[\sum_{k=x}^n\binom{k}{x}=\binom{n+1}{x+1}
\]
由数学归纳法易得。
范德蒙德卷积公式
\[\sum_{k=0}^s\binom{n}{k}\binom{m}{m-k}=\binom{n+m}{s}
\]
考虑生成函数,\(\binom{n}{k}\)的生成函数为\((1+x)^n\),左侧很明显是一个卷积,则右侧的生成函数为\((1+x)^{n+m}\),易证。
由对称性,得:
\[\sum_{k=0}^n\binom{n}{k}\binom{m}{k}=\binom{n+m}{n}
\]
解决
显然,不同质因数之间可以分开处理。考虑对于一个质因子,求出这\(n\)个数中这个质因子的幂次,并排序,得到序列\(a\)。
容易发现,问题就是要求
\[\min\left\{\sum_{k=1}^n\left|x-a_k\right|\right\}
\]
显然,取中位数为最佳。换言之,从最左和最右的两个数开始,依次向内配对。
考虑所有子集中每一个点对的贡献:两侧所取的数的个数必须相等,中间的数可以任意取。则有:
\[\begin{align*}
S&=\sum_{i=1}^n\sum_{j=i}^n(a_j-a_i)2^{j-i-1}\sum_{k=0}^n\binom{i-1}{k}\binom{n-j}{k}\\
&=\sum_{i=1}^n\sum_{j=i}^n(a_j-a_i)2^{j-1-1}\binom{i-1+n-j}{i-1}
\end{align*}
\]
改为枚举\(s=i-1+n-j\),有:
\[\begin{align*}
S&=\sum_{s=0}^{n-1}\sum_{i=0}^s(a_{n-s+i}-a_{i+1})2^{n-s-2}\binom{s}{i}\\
\end{align*}
\]
减号两侧分开处理。
左侧
\[\begin{align*}
S_0&=\sum_{s=0}^{n-1}\sum_{i=0}^sa_{n-s+i}2^{n-s-2}\binom{s}{i}\\
&=\sum_{s=0}^{n-1}\sum_{i=0}^sa_{n-i}2^{n-s-2}\binom{s}{i}\\
&=\sum_{i=0}^{n-1}a_{n-i}\sum_{s=i}^{n-1}2^{n-s-2}\binom{s}{i}\\
&=\sum_{i=1}^{n}a_{i}\sum_{s=n-i}^{n-1}2^{n-s-2}\binom{s}{n-i}\\
&=\sum_{i=1}^{n}a_{i}\sum_{s=1}^{i}2^{s-2}\binom{n-s}{n-i}\\
\end{align*}
\]
记
\[f_x=\sum_{s=1}^{n-x}2^{s-2}\binom{n-s}{x}
\]
则
\[S_0=\sum_{i=1}^na_if_{n-i}
\]
右侧
\[\begin{align*}
S_1&=\sum_{s=0}^{n-1}\sum_{i=0}^sa_{i+1}2^{n-s-2}\binom{s}{i}\\
&=\sum_{i=0}^{n-1}a_{i+1}\sum_{s=i}^{n-1}2^{n-s-2}\binom{s}{i}\\
&=\sum_{i=1}^{n}a_i\sum_{s=i-1}^{n-1}2^{n-s-2}\binom{s}{i-1}\\
&=\sum_{i=1}^na_i\sum_{s=1}^{n-i+1}2^{s-2}\binom{n-s}{i-1}\\
&=\sum_{i=1}^na_if_{i-1}
\end{align*}
\]
合并
\[S=S_0-S_1=\sum_{i=1}^na_i(f_{n-i}-f_{i-1})
\]
问题就转化成如何求\(f_i\)。
显然,这个问题没有简单的形式可以找寻。不妨观察其形式,在Pascal三角形上观察,可以尝试找出一个递归式。
考虑一个局部:
\(f_0\) | \(f_1\) |
---|---|
\(4a\) | |
\(2b\) | \(2a\) |
\(c\) | \(a+b\) |
\(\frac{1}{2}d\) | \(\frac{1}{2}(a+b+c)\) |
则有
\[\begin{align*}
f_0&=4a+2b+c+\frac{1}{2}d\\
f_1&=2a+(a+b)+\frac{1}{2}(a+b+c)\\
&=(2+1+\frac{1}{2})a+(1+\frac{1}{2})b+\frac{1}{2}c\\
&=f_0-\frac{1}{2}(a+b+c+d)
\end{align*}
\]
一般性的,有:
\[\begin{align*}
f_k&=f_{k-1}-\frac{1}{2}\sum_{x=k-1}^{n-1}\binom{x}{k-1}\\
&=f_{k-1}-\frac{1}{2}\binom{n}{k}
\end{align*}
\]
这就可以\(O(n)\)求了。至此,问题解决。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7,inv2=5e8+4;
const int N=300001;
int n,cnt,cx,pri[N],e[N];
bool cm[N];
ll ans,fcn,inv[N],ifc[N],c[N];
vector<int>num[N];
char buf[N*10];
inline ll add(ll a,ll b){return a+b>=mod?a+b-mod:a+b;}
inline ll cut(ll a,ll b){return a-b<0?a-b+mod:a-b;}
inline ll mul(ll a,ll b){return a*b%mod;}
ll fpow(ll a,ll b){ll bs=1;while(b){if(b&1)bs=mul(bs,a);a=mul(a,a);b>>=1;}return bs;}
inline ll C(int k){return mul(fcn,mul(ifc[k],ifc[n-k]));}
void init(){
for(int i=2;i<N;i++){
if(!cm[i]){pri[++cnt]=i;e[i]=cnt;}
for(int j=1;j<=cnt&&i*pri[j]<N;j++){
cm[i*pri[j]]=true;
e[i*pri[j]]=j;
if(i%pri[j]==0)break;
}
}
fcn=inv[1]=ifc[0]=1;
for(int i=1;i<=n;i++)fcn=mul(fcn,i);
for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
for(int i=1;i<=n;i++)ifc[i]=mul(ifc[i-1],inv[i]);
c[0]=mul(cut(fpow(2,n),1),inv2);
for(int i=1;i<n;i++)c[i]=cut(c[i-1],mul(C(i),inv2));
}
inline ll f(int k){return cut(c[n-k],c[k-1]);}
inline int rd(){
int s=0;
while(buf[cx]<'0'||buf[cx]>'9')++cx;
while('0'<=buf[cx]&&buf[cx]<='9')s=10*s+buf[cx++]-'0';
return s;
}
int main(){
fread(buf,sizeof(char),N*10,stdin);
n=rd();
init();
for(int i=1;i<=n;i++){
int a=rd();
while(a>1){
int x=e[a],s=0;
while(a%pri[x]==0){a/=pri[x];s++;}
num[x].push_back(s);
}
}
for(int i=1;i<=cnt;i++){
int s=num[i].size();
sort(num[i].begin(),num[i].end());
for(int j=0;j<s;j++)ans=add(ans,mul(num[i][j],f(n-s+j+1)));
}
printf("%lld\n",ans);
}