HDU3693 Math Teacher's Homework ---- 數位DP

HDU3693 Math Teacher's Homework

一句話題意

給定$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 }
相關文章
相關標籤/搜索