考虑没有 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=1∏kpiqi。
设 b i = ∏ j = 1 k p j x i , j b_i=\prod\limits_{j=1}^kp_j^{x_{i,j}} bi=j=1∏kpjxi,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=1∏kpjaixi,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=1∏mbiai=j=1∏kpji=1∑maixi,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=1∑maixi 的方案数再乘起来即可。
求这个方案数是一个背包 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=1∑maixi 的方案数。
那么现在加上 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,j∈sx,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=1∏Bf(∣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=j∈si∑aj,我们设 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=1∏Bbi′sumai=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=B∪C 且 B ∩ C = ∅ B\cap C=\emptyset B∩C=∅,即能看作将集合 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,k1∑k1!1i=1∏k1f(∣s1,i∣)⎠⎞⎝⎛s2=s2,1+⋯+s2,k2∑k2!1i=1∏k2f(∣s2,i∣)⎠⎞⋯⎝⎛sB=sB,1+⋯+sB,kB∑kB!1i=1∏kBf(∣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=1∏B⎝⎛∣si∣=xi,1+⋯+xi,ki∑ki!1(xi,1,⋯,xi,ki∣si∣)j=1∏kif(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=1∑cwi。
那么这种情况会被 ∣ 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,ki∣si∣) 而被算重 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=1∏B⎝⎛∣si∣=xi,1+⋯+xi,ki∑ki!1(xi,1,⋯,xi,ki∣si∣)j=1∏kif(xi,j)⎠⎞i=1∏B⎝⎛∣si∣=xi,1+⋯+xi,ki∑ki!∣si∣!j=1∏kixi,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=1∏B⎝⎛∣si∣=xi,1+⋯+xi,ki∑ki!∣si∣!j=1∏kixi,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+⋯xk∑k!∣s∣!j=1∏kxj!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)=i≥1∑i!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+⋯xk∑k!∣s∣!j=1∏kxj!f(xj)∣s∣!k≥1∑k!1[x∣s∣]Fk(x)∣s∣−1)∣s∣−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}
[x∣s∣](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=i≥0∑(−1)ixi=i≥1∑i(−1)i−1xi
根据
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)i−1
得到
f
(
i
)
=
(
−
1
)
i
−
1
(
i
−
1
)
!
f(i)=(-1)^{i-1}(i-1)!
f(i)=(−1)i−1(i−1)!。
代入原来的式子求 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
*/