[数位DP 多重背包计数] BZOJ5003. 与链

来源:互联网 发布:淘宝外贸原单江苏南通 编辑:程序博客网 时间:2024/06/01 09:11

每一位二进制分开考虑

那么在一个合法的序列中,一定是前面几个数当前二进制位是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;}
原创粉丝点击