給定$n, k以及m_1, m_2, m_3, ..., m_n$求$x_1 \oplus x_2 \oplus x_3 \oplus ... \oplus x_n == K(x_1 \leq m_1, x_2 \leq m_2...)$ 的方案數。spa
一開始口糊了一下,而後寫代碼的時候發現很多東西沒考慮周到,因而就看起了題解。code
咱們首先須要發現一個重要的性質:blog
若是某一位上不受m限制(也就是選0或選1均可以)那麼不管其它數的這一位位選什麼均可以經過這一位來變成結果和K的這一位相等string
爲了不來自$x <= m$的麻煩,咱們首先讓$m ++$, 使條件變爲$x < m$。it
而後按照數位dp的套路對位分析。io
首先假設咱們處理到了第j位,而後從高位到$j + 1$位都已經到了最大值class
而後第$j$位因爲要小於m,因此m的這一位必然1,而後j的這一位必然是0統計
而後按照套路咱們發現若是這一位咱們選了0,那麼後面的位隨便選都不會大於mstatic
爲了方便dp,咱們令每一位最先容許隨便選的那個$x_i$爲$A_j$,這個數將在後面被限制以使其它自由位達到K上對應位的要求di
咱們記第j位上的第i個數字爲自由的,當且僅當這個位不是被m限制了(即第i個數從高位枚舉到第一個比m小的位置),且不是那些被最先選擇(上一行的定義)限制的數字。
而後每一位上的方案數就是$2^{自由數個數-1}$
因而咱們設$dp[i][j][0/1]$表示第i個數的「第i個數從高位枚舉到第一個比m小的位置」爲j,此位的異或值爲0/1
下面咱們記
$num[i][j]$爲第i個數字第j位
$sum[i][j]$爲j位上從第一個數字異或到第i個數字的結果
而後分狀況(自由數位置)討論從狀態$dp[i - 1][k][r]$(注意大小寫)(注意下面$2^x$的下標)轉移,若
m此位能夠有不一樣限制,即$num[i][j] == 1$
$j < k$:$dp[i][j][sum[i - 1][j]] += dp[i - 1][k][r] * 2^k$
$j > k$:$dp[i][k][r \oplus sum[i - 1][j]] += dp[i - 1][k][r] * 2^j$
$j == k$:$dp[i][j][r] += dp[i - 1][k][r] * 2^k$
最後要求$k[j] == sum[n][j]$的時候才能統計入答案
(然而我並不知道怎麼用Latex打出'^' ......)
代碼以下:
1 #include <cstdio> 2 3 #include <bitset> 4 #include <cstring> 5 6 using namespace std; 7 8 char buf[11111111], *pc = buf; 9 10 inline void Main_Init(){ 11 static bool inited = false; 12 if(inited) fclose(stdin), fclose(stdout); 13 else { 14 fread(buf, 1, 11111111, stdin); 15 inited = true; 16 } 17 } 18 19 inline int read(){ 20 int num = 0; 21 char c; 22 while((c = *pc ++) < 48); 23 while(num = num * 10 + c - 48, (c = *pc ++) >= 48); 24 return num; 25 } 26 27 //Source Code 28 29 const int MAXN = 55; 30 const int MAXM = 33; 31 const int MODS = 1000000003; 32 33 int n, ans; 34 int x[MAXN]; 35 unsigned int bin[MAXM]; 36 int dp[MAXN][MAXM][2]; 37 38 bitset<32> K, num[MAXN], sum[MAXN]; 39 40 int main(){ 41 Main_Init(); 42 for(int i = 0; i < 32; i++) bin[i] = 1 << i; 43 while(n = read(), n){ 44 K = read(); 45 for(int i = 1; i <= n; i++) 46 num[i] = x[i] = read() + 1; 47 memset(sum, 0, sizeof(sum)), memset(dp, 0, sizeof(dp)); 48 ans = 0; 49 dp[0][0][0] = 1; 50 for(int j = 0; j < 32; j++) sum[0][j] = num[0][j]; 51 for(int i = 1; i <= n; i++) 52 for(int j = 0; j < 32; j++) 53 sum[i][j] = sum[i - 1][j] ^ num[i][j]; 54 for(int i = 1; i <= n; i++){ 55 for(int j = 0; j < 32; j++){ 56 if(!num[i][j]) continue; 57 for(int k = 0; k < 32; k++){ 58 for(int r = 0; r < 2; r++){ 59 if(dp[i - 1][k][r]){ 60 if(j > k) dp[i][j][sum[i - 1][j]] = (dp[i][j][sum[i - 1][j]] + 1ll * dp[i - 1][k][r] * bin[k]) % MODS; 61 else if(j < k) dp[i][k][r ^ num[i][k]] = (dp[i][k][r ^ num[i][k]] + 1ll * dp[i - 1][k][r] * bin[j]) % MODS; 62 else dp[i][j][r] = (dp[i][j][r] + 1ll * dp[i - 1][k][r] * bin[k]) % MODS; 63 } 64 } 65 } 66 } 67 } 68 for(int i = 31; i >= 0 && K[i + 1] == sum[n][i + 1]; i--) 69 ans = (1ll * ans + dp[n][i][K[i]]) % MODS; 70 printf("%d\n", ans); 71 } 72 Main_Init(); 73 return 0; 74 }