首页 > 其他分享 >「解题报告」ARC137F Overlaps

「解题报告」ARC137F Overlaps

时间:2023-01-29 11:37:27浏览次数:47  
标签:Overlaps frac int ++ ret 括号 解题 ARC137F 序列

首先有经典结论,两个实数随机变量相等的概率为 \(0\)。那么在实数上随机若干个数,最后肯定会有一个顺序关系,而我们只关心这个顺序,所以可以把问题变成离散的。

也就是我们现在有 \(2n\) 个点,每次随机选取两个点覆盖,求覆盖不超过 \(k\) 次的概率。

我们可以把这 \(2n\) 个点看做不一定合法的括号序列,我们只需要保证左括号在右括号的左边,并且 \(n\) 种括号可以随便排列,所以总方案数就是 \(\frac{(2n)!}{2^nn!}\)。

考虑如何计数这个东西,我们可以从左往右填,每碰到一个左括号直接填,当碰到右括号时,我们可以将这个右括号与现在剩下的任意一个左括号匹配,所以一种括号序列的方案数就是每个右括号的深度的乘积。把右括号的深度作为序列拿出来,发现该序列满足以下性质:

  • \(1 \le x_i \le k\)
  • \(x_i \ge x_{i - 1} - 1\)
  • \(x_n = 1\)

并且我们发现只要满足这几个条件的序列就能构造出一个相对应的括号序列。所以我们考虑计算所有这样的序列的 \(\prod x_i\) 之和。

最难搞的是第二个条件,考虑用二项式反演容斥掉第二个条件。我们先不管第二个条件,然后将一个序列从 \(x_i \ge x_{i - 1} - 1\) 的位置划分开,这样就得到了若干个 \(x_i \le x_{i - 1} - 2\) 的序列,而后者是容易计数的。所以我们考虑钦定至少 \(i\) 个位置是错误的方案数为 \(f_i\),那么答案就是 \(\sum_{i=0}^n (-1)^i f_i\)。

先考虑怎么计算一整块都满足 \(x_i \le x_{i - 1} - 2\) 的方案数,这个相当于在 \([1, k]\) 中选数,不能选相邻的两个数,可以分治去计算,考虑 \(dp_{l, r, 0/1, 0/1, j}\) 为 \([l, r]\) 区间内选 \(j\) 个数,\(l, r\) 分别选没选的方案数,FFT 合并即可。

再考虑怎么求拼接在一起的方案数,这个比较经典,写出生成函数,那么答案就是 \(\frac{1}{1-F}\)。(或者分治 FFT 计算)

还有一个 \((-1)^i\),直接把 \(\frac{1}{1-F(x)}\) 改成 \(\frac{1}{1-F(-x)}\) 就行了。

别忘了还有第三个条件,所以需要将 \(\frac{1}{1-F(-x)}\) 与选择了 \(1\) 的方案数卷起来。

int n, k;
array<array<Polynomial, 2>, 2> solve(int l, int r) {
    array<array<Polynomial, 2>, 2> ret;
    ret[0][0] = ret[0][1] = ret[1][0] = ret[1][1] = {0};
    if (l == r) {
        ret[0][0] = {1};
        ret[0][1] = {0};
        ret[1][0] = {0};
        ret[1][1] = {0, l};
        return ret;
    }
    int mid = (l + r) >> 1;
    auto L = solve(l, mid), R = solve(mid + 1, r);
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            for (int a = 0; a < 2; a++) {
                for (int b = 0; a + b < 2; b++) {
                    ret[i][j] = ret[i][j] + L[i][a] * R[b][j];
                }
            }
        }
    }
    return ret;
}
int main() {
    scanf("%d%d", &n, &k);
    auto ans = solve(1, k);
    Polynomial a, b;
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            if (i == 1) a = a + ans[i][j];
            b = b + ans[i][j];
        }
    }
    for (int i = 0; i <= a.len; i += 2) {
        a[i] = 1ll * a[i] * (P - 1) % P;
    }
    for (int i = 0; i <= b.len; i += 2) {
        b[i] = 1ll * b[i] * (P - 1) % P;
    }
    a = a * (/*1*/ - b).inv(n + 1);
    int tot = 1;
    for (int i = 1; i <= n; i++) {
        tot = 1ll * tot * (2 * i - 1) % P;
    }
    printf("%lld\n", 1ll * a[n] * qpow(tot, P - 2) % P);
    return 0;
}

标签:Overlaps,frac,int,++,ret,括号,解题,ARC137F,序列
From: https://www.cnblogs.com/apjifengc/p/17072154.html

相关文章

  • AtCoder Beginner Contest 287 解题报告
    AtCoderBeginnerContest287解题报告\(\text{ByDaiRuiChen007}\)ContestLinkA.Majority用map分别统计两种字符串出现的次数并与\(\left\lfloor\dfracn2\righ......
  • 「解题报告」ARC138F KD Tree
    好题!感觉比那些写出DP然后无脑上GF数学方法硬推的题有价值。首先有个朴素的想法:设\(f_{l,r,u,d}\)表示这个矩形的方案数,那么枚举分界点转移。引用大佬的话:直......
  • 深搜与宽搜的解题思路
    写在开头:本文章提供深搜与宽搜的解题思路,无具体题目对应的代码,如想了解,请到个人主页查找,感谢观看。 深度优先搜索(DFS):递归,即函数调用自身,以逐步减小问题的规模。但在......
  • 「解题报告」ARC139D Priority Queue 2
    我困炸了,一个月没有六点起过床了。统计总贡献不好统计,考虑把贡献拆开统计。发现统计每个数出现次数还是不好统计,那就直接把数也拆开。对于每一个\(i\),统计\(\gei\)的......
  • 「解题报告」ARC140F ABS Permutation (Count ver.)
    洛谷题解说这题是“巨大蠢题。这是我见过的最垃圾的ARC,没有之一。”好吧,我不会做巨大蠢题。首先我们可以想到,如果\(|a_i-a_j|=m\),那么\(a_i\)和\(a_j\)一定在......
  • Codeforces Round #846 (Div. 2) 解题报告
    CodeforcesRound#846(Div.2)解题报告\(\text{ByDaiRuiChen007}\)ContestLinkA.HayatoandSchool简单题,发现答案要么是一奇两偶、要么是三个奇数,分别考虑两种......
  • ARC154 解题报告【A-D】
    AtcoderRegularContest154ContestlinkMyresult声明:代码只包含核心代码,交上去会CE!A-SwapDigit设\(a,b\)的第\(i\)位分别为\(a_i,b_i\)。由于\(a_i\)与......
  • ABC286 上分记 & 解题报告
    AtcoderBeginnerContest286contestlinkcontestresult解题记录留坑待填......
  • AtCoder Beginner Contest 286 解题报告
    AtCoderBeginnerContest286解题报告\(\text{ByDaiRuiChen007}\)ContestLinkA.RangeSwap直接模拟交换过程即可时间复杂度\(\Theta(n)\)#include<bits/stdc++......
  • WC2023 解题报告
    WC2023解题报告stairs考虑阶梯的右下折线,称竖线为0,横线为1,从上到下形成一个01序列。原题要求的子楼梯边界格数转化成01序列里靠前的0和靠后的1的位置差。我......