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) 个不同的盒子,球和球没有区别,盒子和盒子有区别,此时方案数为
[inom {n+m-1}{m-1}=inom {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;
}