给定$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 }