Description

\(n\) 只牛,其中部分牛是特殊的,特殊的牛之间至少要隔 \(k\) 只普通牛。求方案数。\(n \le 10^5\)

Solution

可以提供四种解法。

DP + 前缀和

\(f[i]\) 表示放了 \(i\) 只牛,最后一只是特殊牛的方案数,则

\[f[i]=\sum_{j=0}^{i-k-1} f[j] \]

前缀和优化即可。

另一种 DP

\(f[i]\) 表示放了 \(i\) 只牛的方案数,转移时考虑枚举上一只牛是普通还是特殊,则

\[f[i]=f[i-1]+f[i-k-1] \]

注意前几位要特殊处理。

更暴力的 DP

\(f[i][0/1]\) 表示放了 \(i\) 只,最后一只是普通/特殊的方案数,则

\[f[i][0]=f[i-1][0]+f[i-1][1] \\ f[i][1]=f[i-k-1][1]+f[i-k-1][0] \]

显然这个方法化简一下就能直接得到第二种。

组合数学

枚举特殊牛的数量 \(x\),则至少需要 \(k(x-1)\) 只普通牛,多出来的普通牛数量为 \(r=n-x-k(x-1)\),而不同牛被分为 \(x+1\) 个段,因此我们要将 \(r\) 个球投入 \(x+1\) 个不同的盒子,球和球没有区别,盒子和盒子有区别,此时方案数为

\[\binom {n+m-1}{m-1}=\binom {x+r}{x} \]

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 100005;
const int mod = 5000011;

int f[N],n,k;

signed main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=0;i<=k;i++) f[i]=i+1;
    for(int i=k+1;i<=n;i++) f[i]=(f[i-1]+f[i-k-1])%mod;
    cout<<f[n]<<endl;
}

相关文章: