1. 程式人生 > >[數位DP 多重揹包計數] BZOJ5003. 與鏈

[數位DP 多重揹包計數] BZOJ5003. 與鏈

每一位二進位制分開考慮

那麼在一個合法的序列中,一定是前面幾個數當前二進位制位是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; }