题目链接在本地。

首先这是一个环,对于一个环来说,我们肯定是要把展成一条链来做的。常见的展成链的方法是从某一点断开然后长度延长两倍。不过这里可以不用,因为环上的点肯定是要塞人的,因此我们可以假定第一个点一定塞了人。考虑最入门的递推题,上楼梯,一次可以上一阶或者两阶,到最上面有多少种走法。其实此题也是类似,每一个点可以由上一个塞了人的点推过来,不过这里这个步长比较大,因此不能直接暴力去找,但是我们同样可以看到,对于每一个点,我们只需要知道前面 s 个点的和,因此做一个前缀和维护一下就行了。

 

1 #include "bits/stdc++.h"
2 using namespace std;
3 typedef long long LL;
4 const int MAX=1e6+5;
5 const int MOD=123456789;
6 LL n,s;
7 LL f[MAX],sum[MAX];
8 LL calc(LL low,LL high){
9 return (sum[high]-sum[low-1]+MOD)%MOD;
10 }
11 inline LL mx(LL x,LL y){return x>y?x:y;}
12 int main(){
13 LL i,j,ans=0;
14 scanf("%lld%lld",&n,&s);
15 f[0]=sum[0]=0;
16 f[1]=sum[1]=1;
17 for (i=2;i<=n;i++){
18 f[i]=calc(mx(1ll,i-s),i-1);
19 sum[i]=(sum[i-1]+f[i])%MOD;
20 }
21 // for (i=1;i<=n;i++) cout<<f[i]<<' ';cout<<endl;
22 for (i=n-s+1;i<=n;i++)
23 ans=(ans+calc(n-s+1,i))%MOD;
24 printf("%lld",ans);
25 return 0;
26