首页 > 其他分享 >P9387 [THUPC 2023 决赛] 巧克力 题解

P9387 [THUPC 2023 决赛] 巧克力 题解

时间:2023-07-29 19:44:30浏览次数:36  
标签:nl THUPC int 题解 add P9387 return oplus dp

这篇题解会只讲怎么 dp,所以我们这里跳过博弈论的部分。

Let's rephrase the problem statement as follows:

给定 \(n,m\),设 \(x=1\oplus 2\oplus\cdots\oplus n\oplus m\)。求有多少个有序三元组 \((a,b,c)\) 满足:

  • \(a+b+c\le n\) 或 \(a+b+c=m\)(如果都满足需要算两遍)。
  • \((a+b+c)\oplus a\oplus c=x\)。
  • \(a,c\ge 0,b\gt 0\)。

答案对 \(10^9+7\) 取模。

注意到 \(\forall y,y\oplus(y+1)\oplus(y+2)\oplus(y+3)=0\),这样 \(x\) 就可以快速计算了。

首先我们显然只需要解决 \(a+b+c\le n\) 的问题。

对于这种涉及到二进制的计数 dp。我们一般采取 从低位到高位 的顺序 dp,并同时记录进了多少位。另一个经典例题:NOIP 数列。

设 \(f_{i,j,k,l}\) 表示:考虑了 \(a,b,c\) 的最低 \(i\) 位,第 \(i\) 位往第 \(i+1\) 位进位了 \(j\),\(b\) 的低 \(i\) 位是否是 \(0\),\(a+b+c\) 的低 \(i\) 位是否大于 \(n\) 的低 \(i\) 位。转移时枚举 \(a,b,c\) 的第 \(i\) 位是什么即可。答案是 \(f_{60,0,1,0}\)。

代码:

auto dp = [&](ll n) {
  if (n < 0) return 0;
  memset(f, 0, sizeof(f));
  f[0][0][0][0] = 1;
  for (int i = 0; i < N; i++)
    for (int j = 0; j <= 2; j++)
      for (int k = 0; k <= 1; k++)
        for (int l = 0; l <= 1; l++) {
          for (int a = 0; a <= 1; a++)
            for (int b = 0; b <= 1; b++)
              for (int c = 0; c <= 1; c++) {
                int s = (j + a + b + c) & 1; // 计算 (a + b + c) 的第 i 位
                if ((s ^ a ^ c) != ((x >> i) & 1)) continue;
                int nl = (s > ((n >> i) & 1)) || (l && (s == ((n >> i) & 1)));
                add(f[i + 1][(j + a + b + c) / 2][k || b][nl], f[i][j][k][l]);
              }
        }
  return f[N][0][1][0];
};

但是这么写会 T 掉,我们需要将枚举 \(a,b,c\) 的循环展开。这里可以写一个生成代码的程序,然后手动合并能合并的代码。结果如下(没有任何可读性……所以我把两份代码都放到这里了):

auto dp = [&](ll n) {
  if (n < 0) return 0;
  memset(f, 0, sizeof(f));
  f[0][0][0][0] = 1;
  for (int i = 0; i < N; i++)
    for (int j = 0; j <= 2; j++)
      for (int k = 0; k <= 1; k++)
        for (int l = 0; l <= 1; l++) {
          int s, nl;

          s = j & 1;
          nl = (s > ((n >> i) & 1)) || (l && (s == ((n >> i) & 1)));
          if ((s ^ 0) == ((x >> i) & 1)) {
            add(f[i + 1][(j + 0) >> 1][k][nl], f[i][j][k][l]);
            add(f[i + 1][(j + 2) >> 1][k][nl], f[i][j][k][l]);
          } else {
            add(f[i + 1][(j + 2) >> 1][1][nl], f[i][j][k][l]);
            add(f[i + 1][(j + 2) >> 1][1][nl], f[i][j][k][l]);
          }

          s = (j + 1) & 1;
          nl = (s > ((n >> i) & 1)) || (l && (s == ((n >> i) & 1)));
          if ((s ^ 0) == ((x >> i) & 1)) {
            add(f[i + 1][(j + 1) >> 1][1][nl], f[i][j][k][l]);
            add(f[i + 1][(j + 3) >> 1][1][nl], f[i][j][k][l]);
          } else {
            add(f[i + 1][(j + 1) >> 1][k][nl], f[i][j][k][l]);
            add(f[i + 1][(j + 1) >> 1][k][nl], f[i][j][k][l]);
          }
        }
  return f[N][0][1][0];
};

时间复杂度 \(\mathcal O(\log n)\)。

标签:nl,THUPC,int,题解,add,P9387,return,oplus,dp
From: https://www.cnblogs.com/registergen/p/p9387_solution.html

相关文章

  • Educational Codeforces Round 152 (Rated for Div. 2) 题解
    \(6\)题做出来\(3\)题,这一次的D题没能复刻上一次Round888Div.3最后几分钟AC的奇迹A.MorningSandwich大水题,5min时间4min都在翻译题面直接拿\(b\)和\(c+h\)进行比较分类讨论即可单次操作时间复杂度\(O(1)\)B.Monsters首先有一个特别显然、复杂度特别高的......
  • luogu P4069 [SDOI2016] 游戏 题解【李超树+树剖】
    目录题目描述解题思路code题目描述P4069[SDOI2016]游戏一棵树,树上有\(n\)个节点,最初每个节点上有\(1\)个数字:\(123456789123456789\)。有两种操作:\(\centerdot\)选择\(s,t\)两个节点,将路径上的每一个点都变多(\(1\)个变\(2\)个)数字:\(a\timesdis+b\),其中\(dis\)表示该节点......
  • P3979 遥远的国度 题解
    P3979遥远的国度题意一棵树,\(n\le10^5\),三个操作,\(m\le10^5\),点带权。换根路径推平子树查最小值思路如果没有换根,操作2,3是裸的树剖,考虑换根后的询问如何处理。显然不能再做一遍树剖,只能假装我们换根了,询问可以分成四种情况,令原根为\(root\),新根为\(id\),查询点......
  • luogu P3733 [HAOI2017] 八纵八横 题解【线段树分治+线性基+可撤销并查集+bitset】
    目录题目大意解题思路code题目大意题目链接给出一张\(n\)个点\(m\)条边的连通无向图,边带边权\(w_i\)。有以下三种操作,共\(q\)次:\(\centerdot\)在点\(x,y\)之间加入一条边权为\(w_i\)的边,如果这是第\(i\)个此种操作,则记这条新边为第\(i\)条。\(\centerdot\)将第\(k......
  • P9459 浴眼盯真 题解
    由于我不会使用正则表达式,所以我只能使用基础Python语法QwQ。[input().split()for_inrange(int(input()))]是个列表生成器,效果是产生一个长度为\(T\)的列表,列表的元素是以每一行以空格为分割符的字符串列表。for(a,b,c,d)in[]可以用\(a,b,c,d\)来复制列表中每个元素......
  • P9451 [ZSHOI-R1] 新概念报数 题解
    满足\(\operatorname{popcount}(x)<3\)的数实际上很少,直接把所有这些数扔到set里面,询问就返回set中\(x\)的下一个元素即可。记得开longlong。set内的元素数量是\(\log^2w\),所以复杂度是\(\mathcalO(\log^2w\log\log^2w+T\log\log^2w)=\mathcalO(\log^2w\log\logw......
  • 【题解】Luogu[P4711] 「化学」相对分子质量
    Link一道简单的模拟题,评绿可能有点高了。因为没有括号嵌套,难度瞬间降了一个档次,我们直接对着化学式扫一遍即可。若扫到左括号,说明接下来都是在括号内的,我们标记一下。若扫到大写字母,说明出现了一个新的元素,那么我们就看后面是否有下标,若有则类似于快读的方式直接处理后面的数......
  • [USACO13DEC] The Bessie Shuffle S 洗牌 题解
    提供一种思路,可以做到\(O(n)\)。目前是全OJ最优解,跑到了79ms。update2023.07.29完工,期望无bug(暑假快乐吖o( ̄▽ ̄)ブ)update2023.07.27(要原题检测了,先占个坑,有时间再补)原题大意P3095[USACO13DEC]TheBessieShuffleS有\(n\)张牌,每次取出\(m\;(m<n)\)张牌进行置换操作。操......
  • CF858C 题解
    洛谷链接&CF链接本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读。题目简述给你一个均为小写字母的字符串,如果它的子串同时满足:三个连着的辅音字母。这一段连着的辅音字母不是全部一样的。就认为它不合法。现在要求用最少的空格隔开这个字符串,使得它变成......
  • AT_agc022_a 题解
    洛谷链接&Atcoder链接本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读。题目简述给定字符串\(S\),仅包含互不相同的小写字母,你需要找到仅包含互不相同的小写字母的字符串中,第一个字典序比它大的字符串,如果找不到输出\(-1\)。(\(|S|\le26\))思路这篇题解......