每一位二进制分开考虑
那么在一个合法的序列中,一定是前面几个数当前二进制位是1,其他都是0
数位DP,每一位的1最多出现k次,这就是一个多重背包
多重背包转移用前缀和优化就好了
O(nlogn)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=100010,P=1e9+9;
int n,K,f[20][N][2];
int tmp[N];
inline void add(int &x,int y){
(x+=y)%=P;
}
int main(){
scanf("%d%d",&K,&n);
f[17][0][1]=1;
for(int i=17;i;i--){
int t=1<<i-1;
for(int k=0;k<=1;k++){
if(k==1 && !((n>>i-1)&1)){
for(int j=0;j<=n;j++) add(f[i-1][j][k],f[i][j][k]);
continue;
}
for(int j=0;j<=n;j++) add(f[i-1][j][0],f[i][j][k]);
for(int j=0;j<=n;j++)
tmp[j]=(f[i][j][k]+(j-t<0?0:tmp[j-t]))%P;
for(int j=t;j<=n;j++){
int nxt=(k==1 && ((n>>i-1)&1));
add(f[i-1][j][nxt],(tmp[j-t]-(j-1LL*t*(K+1)<0?0:tmp[j-t*(K+1)]))%P);
}
}
}
int ans=(f[0][n][0]+f[0][n][1])%P;
cout<<(ans+P)%P<<endl;
return 0;
}