【XSY3657】因数分解(容斥,DP)

考虑没有 b i b_i bi 的限制怎么做。

先把 n ! n! n! 质因数分解: n ! = ∏ i = 1 k p i q i n!=\prod\limits_{i=1}^kp_i^{q_i} n!=i=1kpiqi

b i = ∏ j = 1 k p j x i , j b_i=\prod\limits_{j=1}^kp_j^{x_{i,j}} bi=j=1kpjxi,j,那么 b i a i = ∏ j = 1 k p j a i x i , j b_i^{a_i}=\prod\limits_{j=1}^kp_j^{a_ix_{i,j}} biai=j=1kpjaixi,j ∏ i = 1 m b i a i = ∏ j = 1 k p j ∑ i = 1 m a i x i , j \prod\limits_{i=1}^m b_i^{a_i}=\prod\limits_{j=1}^kp_j^{\sum\limits_{i=1}^ma_ix_{i,j}} i=1mbiai=j=1kpji=1maixi,j

每一个质因数 p j p_j pj 是独立的,于是我们对于每一个 q j q_j qj 求出把 q j q_j qj 分解成 ∑ i = 1 m a i x i \sum\limits_{i=1}^ma_ix_{i} i=1maixi 的方案数再乘起来即可。

求这个方案数是一个背包 DP 的事情,具体实现上我们 DP 求出 f v f_v fv 表示将 v v v 分解成 ∑ i = 1 m a i x i \sum\limits_{i=1}^ma_ix_{i} i=1maixi 的方案数。

那么现在加上 b i b_i bi 的限制后我们就考虑容斥。

对于某一种 { b i } \{b_i\} {bi} 的方案,将所有的 i i i 划分成若干组,每一组里的 b i b_i bi 是相同的,但不保证所有相同的 b i b_i bi 划分进同一组,然后设一共有 B B B 组,分别是 s 1 , s 2 , ⋯   , s B s_1,s_2,\cdots,s_B s1,s2,,sB。 那么满足 ∀ i , j ∈ s x , b i = b j \forall i,j\in s_x,b_i=b_j i,jsx,bi=bj

考虑设容斥系数 f ( s i ) f(s_i) f(si) 使得:
a n s = ∑ 枚 举 划 分 T = ( s 1 , s 2 , ⋯   , s B ) ( ∏ i = 1 B f ( ∣ s i ∣ ) ) d p ( T ) ans=\sum_{枚举划分T=(s_1,s_2,\cdots,s_B)}\left(\prod_{i=1}^Bf(|s_i|)\right)dp(T) ans=T=(s1,s2,,sB)(i=1Bf(si))dp(T)
其中 d p ( T ) dp(T) dp(T) 表示满足划分 T T T b b b 的方案数。

换言之,设 s u m a i = ∑ j ∈ s i a j suma_i=\sum\limits_{j\in s_i}a_j sumai=jsiaj,我们设 s i s_i si 这一组内是都有相同的 b i ′ b'_i bi,此时组已经是分好了的,如果我们能确定 b i ′ b'_i bi,我们就能确定原来所有的 b i b_i bi,也就是我们要求 b i ′ {b_i'} bi 使得 ∏ i = 1 B b i ′ s u m a i = n ! \prod\limits_{i=1}^B{b_i'}^{suma_i}=n! i=1Bbisumai=n!,那么 d p ( T ) dp(T) dp(T) 就是 b i ′ {b_i'} bi 的方案数。

注意这里的 b i ′ b_i' bi 并没有要求两两不同,所以我们仍然可以用背包 DP 来求解。

这里插一小段讲一下怎么求解:由于对于不同的 T T T 它的 s u m a i suma_i sumai 是有可能不同的,对于每一种 T T T 都跑一遍背包 DP 显然不现实,那么我们就不妨直接 dfs 枚举 s u m a suma suma 数组是什么(设 M = ∑ a i M=\sum a_i M=ai,那么只需满足 ∑ i s u m a i = M \sum_{i} suma_i=M isumai=M 即可),然后一边枚举一遍跑背包 DP,并对于所有枚举的 s u m a suma suma 数组记录答案。

d p ( T ) dp(T) dp(T) 求解完成,考虑怎么求容斥系数。

那么考虑一种极大的划分 T T T(“极大的” 指这种划分方案中所有相同的 b i b_i bi 都在同一组,即不存在两组的 b i b_i bi 相同),对于某种符合划分 T T T b b b 的方案 S S S,考虑 S S S 在上面答案计算式等号左右的贡献:

  • 显然这种方案对 a n s ans ans 有贡献当且仅当没有一组有多于 1 1 1 个元素(即不存在 i ≠ j i\neq j i=j b i = b j b_i=b_j bi=bj),故对等号左边的贡献为 [ s 1 = s 2 = ⋯ = s B = 1 ] [s_1=s_2=\cdots=s_B=1] [s1=s2==sB=1]

  • 等号右边,如果在枚举另一种划分 T ′ T' T S S S 也被统计进去了(即 S S S 也符合划分 T ′ T' T),当且仅当能将 T T T 的每一组再划分成若干组(可以划分为 1 1 1 组,即不变)而形成划分 T ′ T' T

    于是 S S S 在等号右边的贡献为:(定义 A = B + C A=B+C A=B+C 当且仅当 A = B ∪ C A=B\cup C A=BC B ∩ C = ∅ B\cap C=\emptyset BC=,即能看作将集合 A A A 划分成两个集合 B , C B,C B,C

    ( ∑ s 1 = s 1 , 1 + ⋯ + s 1 , k 1 1 k 1 ! ∏ i = 1 k 1 f ( ∣ s 1 , i ∣ ) ) ( ∑ s 2 = s 2 , 1 + ⋯ + s 2 , k 2 1 k 2 ! ∏ i = 1 k 2 f ( ∣ s 2 , i ∣ ) ) ⋯ ( ∑ s B = s B , 1 + ⋯ + s B , k B 1 k B ! ∏ i = 1 k B f ( ∣ s B , i ∣ ) ) \left(\sum_{s_1=s_{1,1}+\cdots+s_{1,k_1}}\dfrac{1}{k_1!}\prod_{i=1}^{k_1}f(|s_{1,i}|)\right)\left(\sum_{s_2=s_{2,1}+\cdots+s_{2,k_2}}\dfrac{1}{k_2!}\prod_{i=1}^{k_2}f(|s_{2,i}|)\right)\cdots\left(\sum_{s_B=s_{B,1}+\cdots+s_{B,k_B}}\dfrac{1}{k_B!}\prod_{i=1}^{k_B}f(|s_{B,i}|)\right)\\ s1=s1,1++s1,k1k1!1i=1k1f(s1,i)s2=s2,1++s2,k2k2!1i=1k2f(s2,i)sB=sB,1++sB,kBkB!1i=1kBf(sB,i)
    (除以 k 1 ! k_1! k1! 是因为对于某一种 s 1 = s 1 , 1 + ⋯ + s 1 , k 1 s_1=s_{1,1}+\cdots+s_{1,k_1} s1=s1,1++s1,k1 它会被计算 k 1 k_1 k1 次)

    发现与具体划分的集合长啥样无关,只和划分的集合的大小有关,于是转为枚举集合的大小:
    ∏ i = 1 B ( ∑ ∣ s i ∣ = x i , 1 + ⋯ + x i , k i 1 k i ! ( ∣ s i ∣ x i , 1 , ⋯   , x i , k i ) ∏ j = 1 k i f ( x i , j ) ) \prod_{i=1}^B\left(\sum_{|s_i|=x_{i,1}+\cdots+x_{i,k_i}}\dfrac{1}{k_i!}\dbinom{|s_i|}{x_{i,1},\cdots,x_{i,k_i}}\prod_{j=1}^{k_i}f(x_{i,j})\right) i=1Bsi=xi,1++xi,kiki!1(xi,1,,xi,kisi)j=1kif(xi,j)
    从上一步枚举集合跳到这一步枚举集合大小看似非常直接,但系数仍为 1 k i ! \dfrac{1}{k_i!} ki!1 的原因实际上需要理性证明:

    考虑 ∣ s i ∣ |s_i| si 的某种分解: ∣ s i ∣ = w 1 y 1 + w 2 y 2 + ⋯ + w c y c |s_i|=w_1y_1+w_2y_2+\cdots+w_cy_c si=w1y1+w2y2++wcyc,其中 y i y_i yi 互不相同。显然此时 k i = ∑ i = 1 c w i k_i=\sum\limits_{i=1}^c w_i ki=i=1cwi

    那么这种情况会被 ∣ s i ∣ = x i , 1 + ⋯ + x i , k |s_i|=x_{i,1}+\cdots+x_{i,k} si=xi,1++xi,k 枚举 k i ! w 1 ! w 2 ! ⋯ w c ! \dfrac{k_i!}{w_1!w_2!\cdots w_c!} w1!w2!wc!ki! 次,那么我们就需要除掉 k i ! w 1 ! w 2 ! ⋯ w c ! \dfrac{k_i!}{w_1!w_2!\cdots w_c!} w1!w2!wc!ki!

    同时,这种情况在每次被枚举到时同一种分配方案都会因为 ( ∣ s i ∣ x i , 1 , ⋯   , x i , k i ) \dbinom{|s_i|}{x_{i,1},\cdots,x_{i,k_i}} (xi,1,,xi,kisi) 而被算重 w 1 ! w 2 ! ⋯ w c ! w_1!w_2!\cdots w_c! w1!w2!wc! 次,那么我们就需要除掉 w 1 ! w 2 ! ⋯ w c ! w_1!w_2!\cdots w_c! w1!w2!wc!

    于是需要除掉 k i ! w 1 ! w 2 ! ⋯ w c ! × w 1 ! w 2 ! ⋯ w c ! = k i ! \dfrac{k_i!}{w_1!w_2!\cdots w_c!}\times w_1!w_2!\cdots w_c!=k_i! w1!w2!wc!ki!×w1!w2!wc!=ki!

    化简一下:
    ∏ i = 1 B ( ∑ ∣ s i ∣ = x i , 1 + ⋯ + x i , k i 1 k i ! ( ∣ s i ∣ x i , 1 , ⋯   , x i , k i ) ∏ j = 1 k i f ( x i , j ) ) = ∏ i = 1 B ( ∑ ∣ s i ∣ = x i , 1 + ⋯ + x i , k i ∣ s i ∣ ! k i ! ∏ j = 1 k i f ( x i , j ) x i , j ! ) \begin{aligned} &\prod_{i=1}^B\left(\sum_{|s_i|=x_{i,1}+\cdots+x_{i,k_i}}\dfrac{1}{k_i!}\dbinom{|s_i|}{x_{i,1},\cdots,x_{i,k_i}}\prod_{j=1}^{k_i}f(x_{i,j})\right)\\ =&\prod_{i=1}^B\left(\sum_{|s_i|=x_{i,1}+\cdots+x_{i,k_i}}\dfrac{|s_i|!}{k_i!}\prod\limits_{j=1}^{k_i}\dfrac{f(x_{i,j})}{x_{i,j}!}\right)\\ \end{aligned} =i=1Bsi=xi,1++xi,kiki!1(xi,1,,xi,kisi)j=1kif(xi,j)i=1Bsi=xi,1++xi,kiki!si!j=1kixi,j!f(xi,j)

现在令等号左右贡献相等:
[ ∣ s 1 ∣ = ∣ s 2 ∣ = ⋯ ∣ s B ∣ = 1 ] = ∏ i = 1 B ( ∑ ∣ s i ∣ = x i , 1 + ⋯ + x i , k i ∣ s i ∣ ! k i ! ∏ j = 1 k i f ( x i , j ) x i , j ! ) [|s_1|=|s_2|=\cdots |s_B|=1]=\prod_{i=1}^B\left(\sum_{|s_i|=x_{i,1}+\cdots+x_{i,k_i}}\dfrac{|s_i|!}{k_i!}\prod\limits_{j=1}^{k_i}\dfrac{f(x_{i,j})}{x_{i,j}!}\right) [s1=s2=sB=1]=i=1Bsi=xi,1++xi,kiki!si!j=1kixi,j!f(xi,j)
显然如果下式满足,上式也满足:
[ ∣ s ∣ = 1 ] = ∑ ∣ s ∣ = x 1 + x 2 + ⋯ x k ∣ s ∣ ! k ! ∏ j = 1 k f ( x j ) x j ! [|s|=1]=\sum_{|s|=x_1+x_2+\cdots x_{k}}\dfrac{|s|!}{k!}\prod_{j=1}^k\dfrac{f(x_j)}{x_j!} [s=1]=s=x1+x2+xkk!s!j=1kxj!f(xj)
注意到这里有个 EGF 的形式,即如果我们设 F ( x ) = ∑ i ≥ 1 f ( i ) i ! x i F(x)=\sum\limits_{i\geq 1}\dfrac{f(i)}{i!}x^i F(x)=i1i!f(i)xi,那么就有:
[ ∣ s ∣ = 1 ] = ∑ ∣ s ∣ = x 1 + x 2 + ⋯ x k ∣ s ∣ ! k ! ∏ j = 1 k f ( x j ) x j ! = ∣ s ∣ ! ∑ k ≥ 1 1 k ! [ x ∣ s ∣ ] F k ( x ) = ∣ s ∣ ! [ x ∣ s ∣ ] ( ∑ k ≥ 0 1 k ! F k ( x ) − 1 ) = ∣ s ∣ ! [ x ∣ s ∣ ] ( e F ( x ) − 1 ) \begin{aligned} \big[|s|=1\big]=&\sum_{|s|=x_1+x_2+\cdots x_{k}}\dfrac{|s|!}{k!}\prod_{j=1}^k\dfrac{f(x_j)}{x_j!}\\ =&|s|!\sum_{k\geq 1}\dfrac{1}{k!}[x^{|s|}]F^k(x)\\ =&|s|![x^{|s|}]\left(\sum_{k\geq 0}\dfrac{1}{k!}F^k(x)-1\right)\\ =&|s|![x^{|s|}]\left(e^{F(x)}-1\right)\\ \end{aligned} [s=1]====s=x1+x2+xkk!s!j=1kxj!f(xj)s!k1k!1[xs]Fk(x)s![xs](k0k!1Fk(x)1)s![xs](eF(x)1)
于是:
[ x ∣ s ∣ ] ( e F ( x ) − 1 ) = [ ∣ s ∣ = 1 ] ∣ s ∣ ! e F ( x ) = x + 1 F ( x ) = ln ⁡ ( x + 1 ) \begin{aligned} \big[x^{|s|}\big]\left(e^{F(x)}-1\right)&=\dfrac{[|s|=1]}{|s|!}\\ e^{F(x)}&=x+1\\ F(x)&=\ln(x+1) \end{aligned} [xs](eF(x)1)eF(x)F(x)=s![s=1]=x+1=ln(x+1)
考虑通过求导拆掉 ln ⁡ \ln ln
F ′ ( x ) = 1 x + 1 = ∑ i ≥ 0 ( − 1 ) i x i F ( x ) = ∑ i ≥ 1 ( − 1 ) i − 1 i x i \begin{aligned} F'(x)&=\dfrac{1}{x+1}=\sum_{i\geq 0}(-1)^{i}x^i\\ F(x)&=\sum_{i\geq 1}\dfrac{(-1)^{i-1}}{i}x^i \end{aligned} F(x)F(x)=x+11=i0(1)ixi=i1i(1)i1xi
根据 F ( x ) F(x) F(x) 的定义就有:
f ( i ) i ! = ( − 1 ) i − 1 i \dfrac{f(i)}{i!}=\dfrac{(-1)^{i-1}}{i} i!f(i)=i(1)i1
得到 f ( i ) = ( − 1 ) i − 1 ( i − 1 ) ! f(i)=(-1)^{i-1}(i-1)! f(i)=(1)i1(i1)!

代入原来的式子求 a n s ans ans 即可。

至于 DP 的具体过程,注意到我们每次枚举需要的只是所有 s i s_i si 的大小和所有的 s u m a i suma_i sumai,于是可以以这两个东西当做维度来 DP。

具体过程详见代码:

#include<bits/stdc++.h>

#define A 35
#define N 10010

using namespace std;

namespace modular
{
	const int mod=1000000007;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
	inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
	inline void Mul(int &x,int y){x=1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct data
{
	int size,sum;
	data(){};
	data(int a,int b){size=a,sum=b;}
};

bool operator < (data a,data b)
{
	if(a.sum==b.sum) return a.size<b.size;
	return a.sum<b.sum;
}

int n,m,M,a[A];
int cnt,prime[N];
int maxq,q[N],numq[N];
bool notprime[N];
int fac[A],ifac[A];

map<vector<int>,int>f1;//f1[vec]:当suma数组为vec时,有多少种b的方案(b可以相同)
map<vector<data>,int>f2[2];//f2[pair(size,sum)]:当|si|数组为size、suma数组为sum时,划分T的方案数

int calc(int p)
{
	int ans=0;
	int x=n;
	while(x)
	{
		ans+=x/p;
		x/=p;
	}
	return ans;
}

void init()
{
	fac[0]=1;
	for(int i=1;i<=m;i++) fac[i]=mul(fac[i-1],i);
	ifac[m]=poww(fac[m],mod-2);
	for(int i=m;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
	for(int i=2;i<=n;i++)
	{
		if(!notprime[i])
		{
			prime[++cnt]=i;
			q[i]=calc(i);
			numq[q[i]]++;
			maxq=max(maxq,q[i]);
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
		{
			notprime[i*prime[j]]=1;
			if(!(i%prime[j])) break;
		}
	}
}

int aa[A];
int dp[A][N];

void dfs(int k,int lst,int sum)
{
	if(sum==M)
	{
		int ans=1;
		for(int i=1;i<=maxq;i++)
			Mul(ans,poww(dp[k-1][i],numq[i]));
		vector<int>now;
		for(int i=1;i<k;i++)
			now.push_back(aa[i]);
		f1[now]=ans;
		return;
	}
	for(int i=lst;sum+i<=M;i++)
	{
		aa[k]=i;
		for(int j=0;j<=maxq;j++) dp[k][j]=dp[k-1][j];
		for(int j=i;j<=maxq;j++) Add(dp[k][j],dp[k][j-i]);
		dfs(k+1,i,sum+i);
	}
}

int main()
{
	n=read(),m=read();
	init();
	for(int i=1;i<=m;i++)
	{
		a[i]=read();
		M+=a[i];
	}
	dp[0][0]=1;
	dfs(1,1,0);
	bool lst=0,now=1;
	vector<data>empty;
	f2[now][empty]=1;
	for(int i=1;i<=m;i++)
	{
		swap(now,lst);
		f2[now].clear();
		for(auto it=f2[lst].begin();it!=f2[lst].end();it++)
		{
			vector<data>T=it->first;
			for(int j=0;j<(int)T.size();j++)
			{
				vector<data>nT=T;
				nT[j].sum+=a[i],nT[j].size++;
				sort(nT.begin(),nT.end());
				Add(f2[now][nT],it->second);
			}
			vector<data>nT=T;
			nT.push_back(data(1,a[i]));
			sort(nT.begin(),nT.end());
			Add(f2[now][nT],it->second);
		}
	}
	int ans=0;
	for(auto it=f2[now].begin();it!=f2[now].end();it++)
	{
		vector<data>T=it->first;
		int coef=1;
		for(data s:T) Mul(coef,mul((s.size&1)?1:mod-1,fac[s.size-1]));
		vector<int>tmp;
		for(data s:T) tmp.push_back(s.sum);
		Add(ans,mul(coef,mul(f1[tmp],it->second)));
	}
	sort(a+1,a+m+1);
	int tmp=1;
	for(int i=2;i<=m;i++)
	{
		if(a[i]==a[i-1]) tmp++;
		else
		{
			ans=mul(ans,ifac[tmp]);
			tmp=1;
		}
	}
	ans=mul(ans,ifac[tmp]);
	printf("%d\n",ans);
	return 0;
}
/*
10 6
1 2 2 3 3 3
*/
/*
6 4
1 1 2 1
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值