[SDOI2016]储能表

题解

数位DP似乎正解是找i^j的龟绿
在二进制上做数位(DP),需要同时满足(n,m,k)三个限制条件
那么设(f[i][0/1][0/1][0/1])表示当前到从前往后的第i位,到这一位的位置时是否卡(n)上界,是否卡(m)的上界,是否卡(k)的下界的异或和,(g[i][0/1][0/1][0/1])表示方案数
因为如果异或和小于k就变成0了,那么我们只需要考虑异或和(>=k)的数,然后最后再把(f[])的答案减去(k*g[])

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
# define int long long
const int M = 75 ;
using namespace std ;

inline int read() {
	char c = getchar() ; int x = 0 , w = 1 ;
	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
	return x*w ;
}

bool wn[M] , wm[M] , wk[M] ;
int n , m , k , mod , len ;
int f[M][2][2][2] , g[M][2][2][2] , ans ;
void dfs(int pos , bool upn , bool upm , bool kp) { 
//  当前位数,是否卡n的上界,是否卡m的上界,是否卡k的下界
	if(g[pos][upn][upm][kp]) return ;
	if(pos > len) {
		f[pos][upn][upm][kp] = 0 ; 
		g[pos][upn][upm][kp] = 1 ;
		return ; 
	}
	int ret1 , ret2 , rn = (upn ? wn[pos] : 1) ,
	rm = (upm ? wm[pos] : 1) , kw = wk[pos] ;
	for(int i = 0 ; i <= rn ; i ++)
		for(int j = 0 ; j <= rm ; j ++) {
			if(kp && ((i ^ j) < kw)) continue ;
			dfs(pos + 1 , (upn & (i == rn)) , (upm & (j == rm)) , (kp & ((i ^ j) == kw))) ;
			ret1 = g[pos + 1][(upn & (i == rn))][(upm & (j == rm))][(kp & ((i ^ j) == kw))] % mod ;
			ret2 = f[pos + 1][(upn & (i == rn))][(upm & (j == rm))][(kp & ((i ^ j) == kw))] % mod ;
			g[pos][upn][upm][kp] = (g[pos][upn][upm][kp] + ret1) % mod ;
			f[pos][upn][upm][kp] = (f[pos][upn][upm][kp] + ((i ^ j) << (len - pos)) % mod * ret1 % mod + ret2) % mod ;
		}
}
# undef int
int main() {
# define int long long
	int T = read() ; 
	while(T --) {
		memset(wn , false , sizeof(wn)) ; memset(wm , false , sizeof(wm)) ;
		memset(wk , false , sizeof(wk)) ; len = 0 ;
		memset(f , 0 , sizeof(f)) ; memset(g , 0 , sizeof(g)) ;
		n = read() - 1 ; m = read() - 1 ; k = read() ; mod = read() ;
		for(int i = 0 ; i <= 60 ; i ++) 
			if((n & (1ull << i)) || (m & (1ull << i)) || (k & (1ull << i)))
				len = i + 1 ;
		for(int i = 1 ; i <= len ; i ++) {
			wn[i] = (n & (1ull << (len - i))) ;
			wm[i] = (m & (1ull << (len - i))) ;
			wk[i] = (k & (1ull << (len - i))) ;
		}
		dfs(1 , true , true , true) ;
		ans = ((f[1][1][1][1] % mod - k % mod * g[1][1][1][1] % mod) % mod + mod) % mod ;
		printf("%lld
",ans) ;
	}
	return 0 ;
}
原文地址:https://www.cnblogs.com/beretty/p/10450266.html