zoukankan      html  css  js  c++  java
  • 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...)$ 的方案数。

    题解

    一开始口糊了一下,然后写代码的时候发现不少东西没考虑周到,于是就看起了题解。

    我们首先需要发现一个重要的性质:

    如果某一位上不受m限制(也就是选0或选1都可以)那么无论其它数的这一位位选什么都可以通过这一位来变成结果和K的这一位相等

    为了避免来自$x <= m$的麻烦,我们首先让$m ++$, 使条件变为$x < m$。

    然后按照数位dp的套路对位分析。

    首先假设我们处理到了第j位,然后从高位到$j + 1$位都已经到了最大值

    然后第$j$位由于要小于m,所以m的这一位必然1,然后j的这一位必然是0

    然后按照套路我们发现如果这一位我们选了0,那么后面的位随便选都不会大于m

    为了方便dp,我们令每一位最早允许随便选的那个$x_i$为$A_j$,这个数将在后面被限制以使其它自由位达到K上对应位的要求

    我们记第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 }
    我永远爱19491001
  • 相关阅读:
    关于在windows10中的vmware9.0里面安装的ubuntukylin15.04和windows共享目录的一些反思
    关于最近工程的一些心得
    关于springMVC中component-scan的问题以及springmvc.xml整理
    初学node.js有感三
    初学node.js有感二
    初学node.js有感一
    编译原理——算符优先分析文法(附源代码)
    数据结构与算法系列研究九——排序算法的一些探讨
    LeetCode: Same Tree
    LeetCode: Symmetric Tree
  • 原文地址:https://www.cnblogs.com/CreeperLKF/p/9014438.html
Copyright © 2011-2022 走看看