[SDOI2016]儲能表
阿新 • • 發佈:2019-02-28
ans ems string mage alt src 條件 答案 char
題解
數位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\n",ans) ; } return 0 ; }
[SDOI2016]儲能表