LOJ6274 数字

数字

NiroBC 姐姐脑洞了两个数字 \(x\)\(y\) ,它们满足 \(x \lor y = T\) ,且 \(L_x \le x \le R_x, L_y \le y \le R_y\) , NiroBC 姐姐想知道 \(x \land y\) 有多少种不同的取值,若有多组 \((x, y)\)\(x \land y\) 值相同,则只算一次。

(其中 \(\lor\) 表示按位取或,C/C++中写作|Pascal中写作or

(其中 \(\land\) 表示按位取与,C/C++中写作&Pascal中写作and

题解

仓鼠《动态规划选讲》。

假设知道\(x \lor y = T\)\(x \land y = V\),判断是否可行,可以做一个数位DP。

\(f[i][a][b][c][d]\)表示考虑到第\(i\)位,\(x\)\(L_x\)\(R_x\)的关系,\(y\)\(L_y\)\(R_y\)的关系,这种情况下是否可行。

然后写一个外层DP,把所有内层结果压起来就可以了。

\(F[i][S]\)表示DP到第\(i\)位,DP状态为\(S\)\(V\)有多少个。

转移枚举\(V\)的第\(i\)位是什么,时间复杂度\(O(2^{16}\log T)\)

// f[i][01][01][01][01]
int F[61][1<<16];

IN int state(int a,int b,int c,int d){
	return a|b<<1|c<<2|d<<3;
}
signed main(){
	int T=read<int>();
	int Lx=read<int>(),Rx=read<int>();
	int Ly=read<int>(),Ry=read<int>();
	F[60][1<<state(1,1,1,1)]=1;
	for(int i=59;i>=0;--i){
		int t=T>>i&1;
		int lx=Lx>>i&1,rx=Rx>>i&1;
		int ly=Ly>>i&1,ry=Ry>>i&1;
		for(int s=0;s<1<<16;++s){
			if(!F[i+1][s]) continue;
			for(int q:{0,1}){
				int news=0;
				for(int a:{0,1})for(int b:{0,1})for(int c:{0,1})for(int d:{0,1}){
					if(~s>>state(a,b,c,d)&1) continue;
					for(int x:{0,1})for(int y:{0,1}){
						if((x|y)!=t or (x&y)!=q) continue;
						if(a and x<lx) continue;
						if(b and x>rx) continue;
						if(c and y<ly) continue;
						if(d and y>ry) continue;
						news|=1<<state(a and x==lx,b and x==rx,c and y==ly,d and y==ry);
					}
				}
				F[i][news]+=F[i+1][s];
			}
		}
	}
	int ans=0;
	for(int s=1;s<1<<16;++s) ans+=F[0][s];
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12708684.html