一道综合数学题

阿狸有一个可重集合(A)(A)中有(n)个元素,因此(A)(2n)个子集。对于每个(A)的子集(x),定义(f(x))的值为,使(x)的所有元素都相同的最少操作步数。操作有两种:

  • 选择(x)中的一个元素,把这个数乘上某个质数(p)

  • 选择(x)中的一个元素,把这个数除掉某个质数(p)。这个数必须是(p)的倍数。

阿狸想知道(sumlimits_{xsubset A}f(x))的值,但是由于这个值可能很大,你只要告诉萌萌的阿狸这个数对(1,000,000,007(10^9+7))取模的值。

前置知识

上指标求和公式

[sum_{k=x}^ninom{k}{x}=inom{n+1}{x+1} ]

由数学归纳法易得。

范德蒙德卷积公式

[sum_{k=0}^sinom{n}{k}inom{m}{m-k}=inom{n+m}{s} ]

考虑生成函数,(inom{n}{k})的生成函数为((1+x)^n),左侧很明显是一个卷积,则右侧的生成函数为((1+x)^{n+m}),易证。

由对称性,得:

[sum_{k=0}^ninom{n}{k}inom{m}{k}=inom{n+m}{n} ]

解决

显然,不同质因数之间可以分开处理。考虑对于一个质因子,求出这(n)个数中这个质因子的幂次,并排序,得到序列(a)

容易发现,问题就是要求

[minleft{sum_{k=1}^nleft|x-a_k ight| ight} ]

显然,取中位数为最佳。换言之,从最左和最右的两个数开始,依次向内配对。

考虑所有子集中每一个点对的贡献:两侧所取的数的个数必须相等,中间的数可以任意取。则有:

[egin{align*} S&=sum_{i=1}^nsum_{j=i}^n(a_j-a_i)2^{j-i-1}sum_{k=0}^ninom{i-1}{k}inom{n-j}{k}\ &=sum_{i=1}^nsum_{j=i}^n(a_j-a_i)2^{j-1-1}inom{i-1+n-j}{i-1} end{align*} ]

改为枚举(s=i-1+n-j),有:

[egin{align*} S&=sum_{s=0}^{n-1}sum_{i=0}^s(a_{n-s+i}-a_{i+1})2^{n-s-2}inom{s}{i}\ end{align*} ]

减号两侧分开处理。

左侧

[egin{align*} S_0&=sum_{s=0}^{n-1}sum_{i=0}^sa_{n-s+i}2^{n-s-2}inom{s}{i}\ &=sum_{s=0}^{n-1}sum_{i=0}^sa_{n-i}2^{n-s-2}inom{s}{i}\ &=sum_{i=0}^{n-1}a_{n-i}sum_{s=i}^{n-1}2^{n-s-2}inom{s}{i}\ &=sum_{i=1}^{n}a_{i}sum_{s=n-i}^{n-1}2^{n-s-2}inom{s}{n-i}\ &=sum_{i=1}^{n}a_{i}sum_{s=1}^{i}2^{s-2}inom{n-s}{n-i}\ end{align*} ]

[f_x=sum_{s=1}^{n-x}2^{s-2}inom{n-s}{x} ]

[S_0=sum_{i=1}^na_if_{n-i} ]

右侧

[egin{align*} S_1&=sum_{s=0}^{n-1}sum_{i=0}^sa_{i+1}2^{n-s-2}inom{s}{i}\ &=sum_{i=0}^{n-1}a_{i+1}sum_{s=i}^{n-1}2^{n-s-2}inom{s}{i}\ &=sum_{i=1}^{n}a_isum_{s=i-1}^{n-1}2^{n-s-2}inom{s}{i-1}\ &=sum_{i=1}^na_isum_{s=1}^{n-i+1}2^{s-2}inom{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))

则有

[egin{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*} ]

一般性的,有:

[egin{align*} f_k&=f_{k-1}-frac{1}{2}sum_{x=k-1}^{n-1}inom{x}{k-1}\ &=f_{k-1}-frac{1}{2}inom{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
",ans);
}
原文地址:https://www.cnblogs.com/eztjy/p/13863603.html