Codechef:Counting Hexagons/CNTHEX(状压DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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';
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83302636