版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/83302636
题解:
相当于是找5个数大于特定的数。
这个范围加上相同的限制,状压已经很明显了,随便怎么压一压做数位DP就好了,加上一些剪枝跑得飞快,但转移写起来有点恶心。
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline void up(int &x,int y) {x=add(x,y);}
int A[34],B[34],top,L,k,bin[34];
int low,upi,ans=0;
int f[34][113][(1<<5)+10][2],vis[34][113][(1<<5)+10][2],vs;
int tr[(1<<5)+10][(1<<5)+10],ok[(1<<5)+10];
inline void init() {
for(int i=0;i<(1<<5);i++) {
static int len[5];
for(int z=0;z<=4;z++) len[z]=((i>>z)&1) ? 1 : (z?len[z-1]+1:1);
for(int z=0;z<=4;z++) if(len[z]>k) ok[i]=1;
for(int j=0;j<(1<<5);j++) {
static int anc[5],val[5];
for(int z=0;z<=4;z++) anc[z]=((i>>z)&1) ? z : (z-1);
for(int z=0;z<=4;z++) val[z]=((j>>z)&1) ? 1 : 0;
for(int z=1;z<=4;z++) if(!val[z] && anc[z]!=z && (z?val[z-1]:0)) {tr[i][j]=-1; break;}
if(~tr[i][j]) {
for(int z=0;z<=4;z++)
if(anc[z]==z || (val[z] && !(z?val[z-1]:0))) tr[i][j]|=(1<<z);
}
}
}
}
inline int dfs(int pos,int res,int sta,bool lim) {
if(res>=10) return 0;
if(res<-101) res=-101;
if(!pos) {
if(res>=0 || !(sta&1)) return 0;
return ok[sta] ? 0 : min(upi-low+1,-res);
}
int kth=res+101;
int &s=f[pos][kth][sta][lim];
if(vis[pos][kth][sta][lim]==vs) return s;
s=0;
for(int i=0;i<bin[5];i++) if(~tr[sta][i]) {
if(lim && ((i>>4)&1) && !B[pos]) continue;
up(s,dfs(pos-1,res*2+A[pos]-__builtin_popcount(i),tr[sta][i],lim&&((i>>4)&1)==B[pos]));
}
return vis[pos][kth][sta][lim]=vs, s;
}
inline int solve(int n) {
top=0; ++vs;
while(n) A[++top]=n&1, n>>=1;
for(int i=0;i<=max(top+1,5);i++) bin[i]=1<<i;
return dfs(top,0,0,1);
}
int main() {
cin>>upi>>low>>L>>k;
while(L) B[++top]=L&1, L>>=1;
init();
cout<<solve(low)<<'\n';
}