【题目】
k k k堆石子,每堆石子初始数量均为 n n n,编号 0 0 0~ k − 1 k-1 k−1,第 i i i次操作对第 ( i − 1 ) % k (i-1)\%k (i−1)%k堆石子操作,可以从该堆石子中拿走若干石子(至少要拿走一颗),要求拿走后这堆石子的个数是拿走前这堆石子个数的一个约数。当某堆石子被取走若干石子后变成 1 1 1时结束操作。问最终操作结束于第 i i i堆的方案数 。答案对 985661441 985661441 985661441取模。
其中 n = ∏ i = 1 m p i e i , m , k ≤ 10 , 2 ≤ p i ≤ 1 0 9 , ∑ e i ≤ 1 0 5 , 1 ≤ e i n=\prod^m_{i=1}p_i^{e_i},m,k\leq 10,2\leq p_i \leq 10^9,\sum e_i\leq 10^5,1\leq e_i n=∏i=1mpiei,m,k≤10,2≤pi≤109,∑ei≤105,1≤ei
原题地址
【解题思路】
这个题很难啊qwq,反正我是没有想到的。那么下面引用官方题解
显然每个石子堆最多做 w = ∑ i = 1 m e i w=\sum_{i=1}^m e_i w=∑i=1mei次操作。
现在我们定义 f ( x ) f(x) f(x)为某堆石子做 x x x次操作后恰好变为 1 1 1个的生成函数。那么我们可以得到每个数字做少于 x x x次操作不变为 1 1 1的生成函数也是 f ( x ) f(x) f(x)。(这两个东西显然是一一对应的)
现在统计结束于第 i i i堆石子的情况,我们枚举它是第几次操作时结束的,不妨设为 x x x,那么对应的方案数就是 f ( x + 1 ) i − 1 f ( x ) k − i + 1 f(x+1)^{i-1}f(x)^{k-i+1} f(x+1)i−1f(x)k−i+1,这是因为编号 ≤ i \leq i ≤i的石子堆在 x x x次操作后仍然没有变为 1 1 1,编号 ≥ i \geq i ≥i的石子堆在 x − 1 x-1 x−1次操作后没有变为 1 1 1,只有编号为 i i i的石子堆恰好变为 1 1 1。
那么如果我们知道 f ( x ) f(x) f(x),则可以用 O ( w k ) O(wk) O(wk)的时间解决问题。
考虑 f ( x ) f(x) f(x)的组成,不妨设某种方案第 j j j次操作 e i e_i ei减少了 d ( i , j ) d(i,j) d(i,j),我们知道对于每个 e i e_i ei有 ∑ j = 1 x d ( i , j ) = e i \sum_{j = 1}^{x}{d(i, j)} = e_i ∑j=1xd(i,j)=ei,且对于每个 j j j有 ∑ i = 1 m d ( i , j ) > 0 \sum_{i = 1}^{m}{d(i, j)} \gt 0 ∑i=1md(i,j)>0。
那么 f ( x ) f(x) f(x)就是分配 d ( i , j ) ( 1 ≤ i ≤ m , 1 ≤ j ≤ x ) d(i,j)(1 \leq i \leq m, 1 \leq j \leq x) d(i,j)(1≤i≤m,1≤j≤x)使得它满足上面两个条件的方案数。
如果只考虑第一个条件对应的方案数 g ( x ) g(x) g(x),我们可以规约到一个经典的组合问题,求一个方程非负整数解的个数。
g ( x ) = ∏ i = 1 m ( e i + x − 1 x − 1 ) \displaystyle g(x) = \prod_{i = 1}^{m}{e_i + x - 1 \choose x - 1} g(x)=i=1∏m(x−1ei+x−1)
这个公式可以通过对 x − 1 x-1 x−1个隔板, e i e_i ei个物品的排列数量得到,隔板把区间分成了 x x x块,每块区间中物品的数量对应一个变量,排列的数量等同于隔板选位置的方法数。
观察到如果某些 j j j与第二个条件产生了矛盾,与之相关的 d ( i , j ) d(i,j) d(i,j)都会是零。利用容斥原理可以得到
f ( x ) = ∑ y = 0 x ( − 1 ) x − y ( x y ) g ( y ) \displaystyle f(x) = \sum_{y = 0}^{x}{(-1)^{x - y} {x \choose y} g(y)} f(x)=y=0∑x(−1)x−y(yx)g(y)
可以发现:
f ( x ) x ! = ∑ y = 0 x ( − 1 ) x − y ( x − y ) ! ⋅ g ( y ) y ! \displaystyle \frac{f(x)}{x!} = \sum_{y = 0}^{x}{\frac{(-1)^{x - y}}{(x - y)!} \cdot \frac{g(y)}{y!}} x!f(x)=y=0∑x(x−y)!(−1)x−y⋅y!g(y)
用 拆 系 数 F F T 拆系数FFT 拆系数FFT或 N T T NTT NTT即可。 ( 985661441 = 235 × 2 22 + 1 ) (985661441 = 235 \times 2^{22} + 1) (985661441=235×222+1)
总的时间复杂度是 O ( w log n + w k ) O(w \log n + w k) O(wlogn+wk)。
【参考代码】
#include
using namespace std;
typedef long long LL;
const int N=2e5+10;
const int mod=985661441,g=985661438;
int n,m,k,L,pris;
LL fac[N],ifac[N],f[N],e[N],rev[N<<1],a[N<<1],b[N<<1];
LL qpow(LL x,LL y){LL ret=1;for(;y;y>>=1,x=x*x%mod) if(y&1) ret=ret*x%mod;return ret;}
LL C(int n,int m){return fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
void up(LL &x,LL y){x+=y;if(x>=mod)x-=mod;}
void totinit()
{
fac[0]=fac[1]=1;
for(int i=2;i>1]>>1)|((i&1)<<(L-1)),a[i]=b[i]=0;
for(int i=0;i<=n;++i) a[i]=(i&1)?mod-ifac[i]:ifac[i];
for(int i=1;i<=n;++i)
{
b[i]=ifac[i];
for(int j=1;j<=pris;++j) b[i]=b[i]*C(e[j]+i-1,i-1)%mod;
}
ntt(a,m,1);ntt(b,m,1);
for(int i=0;i
【总结】
论如何构造生成函数计算。