LOJ6274 数字 【dp套dp】

题目描述:求 \(\text{card}(\{x\and y|x\or y=T,x\in [L_x,R_x],y\in [L_y,R_y]\})\)

数据范围:\(T,L_x,R_x,L_y,R_y\le 2^{60}\)

dp套dp经典题?

我们考虑如何验证 \(x\and y=V\) 是否可能成立,这个东西用数位dp做,设 \(f[i][a][b][c][d]\) 表示第 \(i\) 位上,\(x,y\)\(L_x,R_x;L_y,R_y\) 的关系(这里的关系是类似 limit 的“是否顶到上/下界”)是否可行。由于这 \(16\) 个数都是 bool 值,所以我们可以用一个 \(16\) 位二进制数压到一起,设 \(dp[i][S]\) 表示第 \(i\) 位上,\(f\)\(16\) 个值为 \(S\) 的情况下,有多少个 \(V\) 满足。暴力枚举转移即可,时间复杂度 \(O(2^{21}\log T)\),当然这只是一个粗略的上界。

最后答案应该是 \(\sum_{i=1}^{2^{16}-1}dp[0][i]\),因为 \(dp[0][0]\) 表示任何情况下都不符合的情况。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef unsigned long long LL;
template<typename T>
inline void read(T &x){
	int ch = getchar(); x = 0;
	for(;ch < '0' || ch > '9';ch = getchar());
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
LL T, Lx, Rx, Ly, Ry, dp[61][65536], ans;
inline int sta(int a, int b, int c, int d){return a | b << 1 | c << 2 | d << 3;}
int main(){
	read(T); read(Lx); read(Rx); read(Ly); read(Ry);
	dp[60][1 << sta(1,1,1,1)] = 1;
	for(Rint i = 59;~i;-- i){
		int t = T >> i & 1, lx = Lx >> i & 1, rx = Rx >> i & 1, ly = Ly >> i & 1, ry = Ry >> i & 1;
		for(Rint S = 0;S < 65536;++ S) if(dp[i + 1][S])
			for(Rint v = 0;v < 2;++ v){
				int nxt = 0;
				for(Rint SS = 0;SS < 16;++ SS) if(S >> SS & 1){
					int a = SS & 1, b = SS >> 1 & 1, c = SS >> 2 & 1, d = SS >> 3 & 1;
					for(Rint x = 0;x < 2;++ x)
						for(Rint y = 0;y < 2;++ y)
							if((x | y) == t && (x & y) == v && (!a || x >= lx) && (!b || x <= rx) && (!c || y >= ly) && (!d || y <= ry))
								nxt |= 1 << sta(a && x == lx, b && x == rx, c && y == ly, d && y == ry);
				}
				dp[i][nxt] += dp[i + 1][S];
			}
	}
	for(Rint S = 1;S < 65536;++ S) ans += dp[0][S];
	printf("%llu\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/AThousandMoons/p/12719727.html