1. 程式人生 > >Codechef:Counting Hexagons/CNTHEX(狀壓DP)

Codechef:Counting Hexagons/CNTHEX(狀壓DP)

傳送門

題解:
相當於是找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'; }