首页 > 其他分享 >题解 ARC118E【Avoid Permutations】/ SS240928D【d】

题解 ARC118E【Avoid Permutations】/ SS240928D【d】

时间:2024-09-28 20:22:35浏览次数:7  
标签:const ARC118E 题解 Avoid return int operator modint rhs

题目描述

对于一个排列 \(a\),定义其权值如下:
生成一个 \((n + 2) \times (n + 2)\) 的网格图,行列标号为 \(0 ∼ n + 1\),每次可以从 \((i, j)\) 走到 \((i, j + 1)\) 或 \((i + 1, j)\),且不能走到 \((i, a_i)\),权值为从 \((0, 0)\) 走到 \((n + 1, n + 1)\) 的方案数。
现在排列 \(a\) 某些位置被改成了 \(−1\),请求出所有可能的初始排列的权值之和 \(\bmod 998244353\)。

\(n\leq 200\)。

solution

枚举最终路径,考虑有多少个排列能使这个路径走过去。这样的话可以 dp,考虑记录当前走到哪个格子,但是这样\(-1\) 的位置带来的信息会很多,要一直保持不经过 \(-1\) 的对应位置,状态数容易起飞(其实是可以做的),所以考虑我们不考虑 \(-1\) 的位置,开始容斥(???)。施子集容斥,钦定经过其中 \(x\) 个原来为 \(-1\) 的点,其它 \(-1\) 点不管,最后乘上 \((cnt_{-1}-x)!\),不是 \(-1\) 的照常限制。只有在路径上的 \(-1\) 点是有作用的。进行动态规划,记录当前所在格子,已经经过 \(x\) 个 \(-1\) 点,为了防止重复在同一行或列放 \(-1\) 点,再记录两个 bit 表示这一行、列是否已经填过 \(-1\)。转移枚举这个格子上是否放 \(-1\) 点或者往下、右走一步。总复杂度 \(O(n^3)\)。

code

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
template <unsigned umod>
struct modint {/*{{{*/
  static constexpr int mod = umod;
  unsigned v;
  modint() = default;
  template <class T> modint(const T& y) : v(y % mod + (y < 0 ? mod : 0)) {}
  modint& operator+=(const modint& rhs) { v += rhs.v; if (v >= umod) v -= umod; return *this; }
  modint& operator-=(const modint& rhs) { v -= rhs.v; if (v >= umod) v += umod; return *this; }
  modint& operator*=(const modint& rhs) { v = (unsigned)(1ull * v * rhs.v % umod); return *this; }
  friend modint operator+(modint lhs, const modint& rhs) { return lhs += rhs; }
  friend modint operator-(modint lhs, const modint& rhs) { return lhs -= rhs; }
  friend modint operator*(modint lhs, const modint& rhs) { return lhs *= rhs; }
  friend int raw(const modint& self) { return self.v; }
  friend ostream& operator<<(ostream& os, const modint& self) { return os << raw(self); }
};/*}}}*/
using mint = modint<998244353>;
int n, a[210];
bool vis[210];
mint f[210][210][210][2][2], fac[210];
mint ans = 0;
int main() {
#ifndef LOCAL
  cin.tie(nullptr)->sync_with_stdio(false);  
#endif
  cin >> n;
  for (int i = 1; i <= n; i++) cin >> a[i];
  int cnt = n;
  vis[0] = vis[n + 1] = true;
  for (int i = 1; i <= n; i++) if (~a[i]) vis[a[i]] = true, cnt -= 1;
  for (int i = raw(fac[0] = 1); i <= n; i++) fac[i] = fac[i - 1] * i;
  f[0][0][0][0][0] = 1;
  for (int i = 0; i <= n + 1; i++) {
    for (int j = 0; j <= n + 1; j++) if (i < 1 || i > n || a[i] != j) {
      for (int k = 0; k <= cnt; k++) {
        if (a[i] == -1 && !vis[j]) f[i][j][k + 1][1][1] += f[i][j][k][0][0];
        for (int lf : {0, 1}) {
          for (int cf : {0, 1}) {
            if (raw(f[i][j][k][lf][cf])) debug("f[%d][%d][%d][%d][%d] = %d\n", i, j, k, lf, cf, raw(f[i][j][k][lf][cf]));
            f[i + 1][j][k][0][cf] += f[i][j][k][lf][cf];
            f[i][j + 1][k][lf][0] += f[i][j][k][lf][cf];
          }
        }
      }
    }
  }
  for (int k = 0; k <= cnt; k++) ans += (k & 1 ? -1 : 1) * fac[cnt - k] * f[n + 1][n + 1][k][0][0];
  cout << ans << endl;
  return 0;
}

标签:const,ARC118E,题解,Avoid,return,int,operator,modint,rhs
From: https://www.cnblogs.com/caijianhong/p/18438353/solution-ARC118E

相关文章

  • [USACO22DEC] Making Friends P 题解
    T2[USACO22DEC]MakingFriendsP考虑删除一个点,会有如下的点相连接:题目要求如果两两个点建立联系,只会建立一次。所以,神奇地,我们取出当前待删的点所连接的最小的点,将它和剩下的点连接。手摸一下会发现这样就巧妙地给每个改建的边都建了一次。所以用一个set启发式合并就做完......
  • 2. 两数相加题解
    题目描述给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之外,这两个数都不会以0开头。示例1:输入:l1=[2,4,3],l2=[5,6,4......
  • 【自创题】云梯 题面+题解
    题目描述这是晴练P2876云梯的题面。原链接unicornFairy开始了新的学期。学校换了一个新校长,随之而来的是周五放学的时间由晚上七点半延时到了晚上八点半。unicornFairy认为这很不公平,所以她准备抢先一步回家。晚饭后,unicornFairy来到了一处没有监控的围墙旁。小马将援助unicorn......
  • BLE Audio显示连接成功,但没有音乐播放问题解决方案
    背景最近一直在搞这个问题,和原厂一起分析,背景可以参考前面的文章https://blog.csdn.net/Jzj1234555/article/details/142518444?spm=1001.2014.3001.5501https://blog.csdn.net/Jzj1234555/article/details/142595444?spm=1001.2014.3001.5501解决方案今天原厂承认了他......
  • P5165 xtq的棋盘 题解
    这个题也可以用矩阵加速解决。先考虑70pts的做法,我们设\(f_i\)为从\(i\)位置到达\(0\)的期望步数,并尝试用\(f_n\)表示出所有\(f_i\)并利用\(f_0\)解出\(f_n\)然后回带即可。具体地,设\(f_i=a\timesf_n+b\),\(f_{i-1}=c\timesf_n+d\),则由于:\[f_i=pr......
  • Codeforces Round 975 (Div. 2) 题解:D、E
    第一次进前50,上分最爽的一次D.Speedbreaker对\(a\)按照时间升序排序,不难发现,对于升序排序后的数组,当我们搜到时间\(t\)时,记录已经搜过的时间对应原城市编号最小值为\(l\),最大值为\(r\),则我们一定要在\(a_t\)时间之前走过所有\([l,r]\)之间的城市。则若\(r-l+1>a_t\)则无解,因......
  • [USACO22DEC] Breakdown P 题解
    T1[USACO22DEC]BreakdownP比较显然的一点是,一次加一条边/一次删一条边,显然转化,这是显然的一条套路。这题的\(K\le8\),很有意思的数据范围,然后调用我们聪明的人类大脑得知需要用到折半搜索。所以我们只考虑\(K\le4\)的情况,令\(\mathit{st}\)表示折半搜索中考虑的起点。维......
  • [NOIP2017 提高组] 奶酪 题解
    题目背景NOIP2017提高组D2T1题目描述现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。现在,奶酪的下表面有一只小老鼠Jerry,......
  • 洛谷P1827 [USACO3.4] 美国血统 题解
    上题目:题目描述农夫约翰非常认真地对待他的奶牛们的血统。然而他不是一个真正优秀的记帐员。他把他的奶牛们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而不是用图形的方法。你的任务是在被给予奶牛家谱的“树中序遍历”和......
  • 洛谷P1162 填涂颜色题解
    老规矩上题目:题目描述由数字 00 组成的方阵中,有一任意形状的由数字 11 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如:6×66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:如果从某个 00 出发,只向上下左右 44 个方向移动且仅经过其他 00 的情况下,无法......