题解:AT_abc458_e [ABC458E] Count 123
题目传送门
AtCoder
题目大意
用 \(X_1\) 个 \(1\),\(X_2\) 个 \(2\) 和 \(X_3\) 个 \(3\) 组成一个序列,要求相邻两个数 \(a_i\) 和 \(a_{i+1}\) 的绝对值之差 \(|a_{i+1}-a_i| \leq 1\)。
思路
分析条件
注意到 \(|a_{i+1}-a_i| \leq 1\) 意味着:
- \(1\) 和 \(2\) 可以相邻(因为 \(|1-2|=1\))
- \(2\) 和 \(3\) 可以相邻(因为 \(|2-3|=1\))
- \(1\) 和 \(3\) 不能相邻(因为 \(|1-3|=2\))
因此,构造出的序列中相邻的 \(1\) 和 \(3\) 之间必须用 \(2\) 隔开。
所以,我们可以把 \(2\) 当作隔板,把 \(X_2\) 个 \(2\) 排成一排如下:
\(\_,2,\_,2,\_,\dots,\_2,\_,2,\_\)
这 \(X_2\) 个 \(2\) 总共形成了 \(X_2+1\) 个空隙,每个空隙都可以放若干个 \(1\) 或若干个 \(3\),但是 \(1\) 和 \(3\) 不能出现在同一个空隙中。
组合计数
考虑组合计数。
设 \(s=X_2+1\),表示空隙总数。
枚举 \(i\) 满足 \(1 \leq i \leq \min(X_1,s)\),\(j\) 满足 \(1 \leq j \leq \min(X_3,s-i)\)。
接下来可以分四步计算。
1.选空隙
从 \(s\) 个空隙中选择 \(i\) 个放 \(1\),剩余 \(s-i\) 个中选 \(j\) 个放 \(3\):
2.分配 \(1\)
隔板法。
把 \(X_1\) 个 \(1\) 放入 \(i\) 个非空盒子:
3.分配 \(3\)
把 \(X_3\) 个 \(3\) 放入 \(j\) 个非空盒子:
4.求总方案数
总方案数即:
优化
上述公式显然超时,考虑优化掉内层循环。
定义:
其中 \(r\) 为可用的空隙数量(\(r=X_2+1-i=s-i\))
含义:有 \(r\) 个空隙,把 \(X_3\) 个 \(3\) 放入其中(可不放一些空隙)的方案数。
则:
令 \(t=j-1\):
由于 \(\binom{r}{t+1} = \binom{r}{r-1-t}\),所以:
考虑使用范德蒙德卷积:
此处:
- \(n=r\)
- \(m=X_3-1\)
- \(k=r-1\)
所以:
总方案数:
所以,在线性时间复杂度内就可求出答案。
特殊情况
- 若 \(X_3=0\),则内层的贡献必然始终为 \(1\)。每次加上 \(\sum_{i=1}^{\min(X_1,s)} \binom{s}{i} \binom{X_1-1}{i-1}\) 即可。
- 若 \(X_1=0\),与 \(X_3=0\) 同理。
- 若 \(r=0\)(即 \(i=s\))
- 若 \(X_3=0\),则 \(g[0]=1\)。
- 若 \(X_3 \neq 0\),则 \(g[0]=0\)。
代码
AC Code
#include <iostream>
#define int long long
using namespace std;
const int p=998244353;
int ksm(int a,int b,int MOD)
{
int res=1;
while(b)
{
if(b&1)
{
res=(res*a)%MOD;
}
a=(a*a)%MOD;
b>>=1;
}
return res;
}
int f[2000005],fn[2000005],x1,x2,x3,ans,x,g,s;
int c(int n,int m)
{
if(m<0||m>n)
{
return 0;
}
return f[n]*fn[m]%p*fn[n-m]%p;
}
signed main()
{
f[0]=1;
for(int i=1;i<=2000000;i++)
{
f[i]=f[i-1]*i%p;
}
fn[2000000]=ksm(f[2000000],p-2,p);
for(int i=1999999;i>=0;i--)
{
fn[i]=fn[i+1]*(i+1)%p;
}
cin >> x1 >> x2 >> x3;
s=x2+1;
for(int i=1;i<=min(x1,s);i++)
{
x=s-i;
if(x<0)break;
x=c(s,i)*c(x1-1,i-1)%p;
if(x3==0)
{
ans=(ans+x)%p;
}
else
{
if(s-i==0)
{
g=(x3==0?1:0);
}
else
{
g=c(s-i+x3-1,s-i-1);
}
ans=(ans+x*g)%p;
}
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号