首页 > 其他分享 >Luogu P7118

Luogu P7118

时间:2023-06-12 22:13:54浏览次数:65  
标签:sz 场景 frac int Luogu P7118 inv define

题面

题意很清楚,就不复述了。

不难发现,我们首先要求出场景数小于给定 galgame 的 galgame 数量,于是我们需要求出场景数 \(=i\) 的 galgame 数量,设为 \(f_i\)。

考虑根节点,当 A 场景大小为 \(j\) 时,B 场景的大小为 \(i-j-1\)。枚举每个 \(j\),不难得到 \(f_i=\sum\limits_{j=0}^{i-1}f_j\times f_{i-j-1}\),显然这就是卡特兰数的递推式。对于卡特兰数我们有通项公式 \(f_i=\dfrac{\binom{2i}{i}}{i+1}=\dfrac{(2i)!}{i!\,(i+1)!}\),因此我们可以 \(O(n)\) 预处理出每个卡特兰数。

接下来考虑场景数相等的情况,这种情况也可以分为两种:A 场景不同,A 场景相同。

对于 A 场景相同的情况,直接完全交给 B 场景变为子问题即可。

对于 A 场景不同的情况,B 场景可以是任何结构。设 \(m\) 为 A 场景的大小,先考虑大小 \(<m\) 的,这部分贡献是 \(\sum\limits_{j=0}^{m-1}f_j\times f_{n-i-1}\);对于大小 \(=m\) 的情况,递归变成子问题,再乘上 B 场景的情况数即可。

尴尬的是这种方法是 \(O(n^2)\) 的,无法通过本题。

我们发现瓶颈在于 \(\sum\limits_{j=0}^{m-1}f_j\times f_{n-i-1}\),这个东西就是卡特兰数的递推式少了几项。不难发现 \(\sum\limits_{j=0}^{m-1}f_j\times f_{n-i-1}=f_n-\sum\limits_{j=0}^{n-m}f_j\times f_{n-i-1}\),于是每个子问题的操作次数都可以控制在 \(\left\lceil\dfrac{n}{2}\right\rceil\) 以内(\(n\) 为子任务规模),使用启发式合并,时间复杂度降到 \(O(n\log n)\)。

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 1e6 + 5, p = 998244353;
int n, frac[N * 2], inv[N * 2], h[N], s[N], sz[N], ans;
pii a[N];
int qp(int a, int b) {
    int res = 1;
    for(; b; b >>= 1, a = a * a % p)
        if(b & 1) res = res * a % p;
    return res; 
}
void init() {
    cin >> n;
    rep(i, 1, n) cin >> a[i].F >> a[i].S;
    frac[0] = 1;
    rep(i, 1, n * 2) frac[i] = frac[i - 1] * i % p; // 预处理阶乘
    inv[n * 2] = qp(frac[n * 2], p - 2);
    per(i, n * 2 - 1, 0) inv[i] = inv[i + 1] * (i + 1) % p; // 预处理阶乘的逆元
    rep(i, 0, n) h[i] = frac[i * 2] * inv[i] % p * inv[i + 1] % p; // 预处理卡特兰数
}
void dfs(int u) { // 预处理子树大小
    sz[u] = 1;
    if(a[u].F) dfs(a[u].F), sz[u] += sz[a[u].F];
    if(a[u].S) dfs(a[u].S), sz[u] += sz[a[u].S];
}
int solve(int u) {
    int ans = 0;
    if(a[u].F) {
        if(sz[a[u].F] <= sz[a[u].S]) { // 启发式合并
            rep(i, 0, sz[a[u].F] - 1)
                (ans += h[i] * h[sz[u] - i - 1]) %= p;
        } 
        else {
            ans = (ans + h[sz[u]]) % p;
            rep(i, 0, sz[a[u].S])
                ans = ((ans - h[i] * h[sz[u] - i - 1]) % p + p) % p;
        }
        (ans += solve(a[u].F) * h[sz[a[u].S]]) %= p; // 递归变成子问题
    }
    if(a[u].S) (ans += solve(a[u].S)) %= p;
    return ans;
}
signed main() {
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
#endif
    init();
    dfs(1);
    rep(i, 1, n - 1) (ans += h[i]) %= p;
    cout << (ans + solve(1)) % p << endl;
    return 0;
}

标签:sz,场景,frac,int,Luogu,P7118,inv,define
From: https://www.cnblogs.com/untitled0/p/luogu-p7118.html

相关文章

  • Luogu P2580 于是他错误的点名开始了
    于是他错误的点名开始了题目背景XS中学化学竞赛组教练是一个酷爱炉石的人。他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛CON900)。题目描述这之后校长任命你为特派探员,每天记录他的点......
  • Luogu P3435 [POI2006] OKR-Periods of Words
    [POI2006]OKR-PeriodsofWords题面翻译对于一个仅含小写字母的字符串\(a\),\(p\)为\(a\)的前缀且\(p\nea\),那么我们称\(p\)为\(a\)的proper前缀。规定字符串\(Q\)(可以是空串)表示\(a\)的周期,当且仅当\(Q\)是\(a\)的proper前缀且\(a\)是\(Q+Q\)的前缀......
  • Luogu P2375 [NOI2014] 动物园
    [NOI2014]动物园题目描述近日,园长发现动物园中好吃懒做的动物越来越多了。例如企鹅,只会卖萌向游客要吃的。为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习算法。某天,园长给动物们讲解KMP算法。园长:“对于一个字符串\(S\),它......
  • Luogu P4824 [USACO15FEB] Censoring S
    [USACO15FEB]CensoringS题面翻译FarmerJohn为他的奶牛们订阅了GoodHooveskeeping杂志,因此他们在谷仓等待挤奶期间,可以有足够的文章可供阅读。不幸的是,最新一期的文章包含一篇关于如何烹制完美牛排的不恰当的文章,FJ不愿让他的奶牛们看到这些内容。FJ已经根据杂志的所有文字,......
  • Luogu P3375 【模板】KMP字符串匹配
    【模板】KMP字符串匹配题目描述给出两个字符串\(s_1\)和\(s_2\),若\(s_1\)的区间\([l,r]\)子串与\(s_2\)完全相同,则称\(s_2\)在\(s_1\)中出现了,其出现位置为\(l\)。现在请你求出\(s_2\)在\(s_1\)中所有出现的位置。定义一个字符串\(s\)的border为\(s\)......
  • Luogu P3167 [CQOI2014]通配符匹配
    [CQOI2014]通配符匹配题目描述几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(”“'),可以匹配0个及以上的任意字符:另一个是问号(”?“),可以匹配恰好一个任意字符。现在需要你编写一个程序,对于给定的文件名列表和一个包......
  • Luogu P4591 [TJOI2018]碱基序列
    [TJOI2018]碱基序列题目描述小豆参加了生物实验室。在实验室里,他主要研究蛋白质。他现在研究的蛋白质是由\(k\)个氨基酸按一定顺序构成的。每一个氨基酸都可能有\(a\)种碱基序列\(s_{i,j}\)构成。现在小豆有一个碱基串\(s\),小豆想知道在这个碱基上都多少中不同的组合方式可能得......
  • Luogu P4159 [SCOI2009] 迷路
    [SCOI2009]迷路题目背景windy在有向图中迷路了。题目描述该有向图有\(n\)个节点,节点从\(1\)至\(n\)编号,windy从节点\(1\)出发,他必须恰好在\(t\)时刻到达节点\(n\)。现在给出该有向图,你能告诉windy总共有多少种不同的路径吗?答案对\(2009\)取模。注意:windy......
  • Luogu P1939 【模板】矩阵加速(数列)
    【模板】矩阵加速(数列)题目描述已知一个数列\(a\),它满足:\[a_x=\begin{cases}1&x\in\{1,2,3\}\\a_{x-1}+a_{x-3}&x\geq4\end{cases}\]求\(a\)数列的第\(n\)项对\(10^9+7\)取余的值。输入格式第一行一个整数\(T\),表示询问个数。以下\(T\)行,每行一个正......
  • Luogu P3390 【模板】矩阵快速幂
    【模板】矩阵快速幂题目背景一个\(m\timesn\)的矩阵是一个由\(m\)行\(n\)列元素排列成的矩形阵列。即形如\[A=\begin{bmatrix}a_{11}&a_{12}&\cdots&a_{1n}\\a_{21}&a_{22}&\cdots&a_{2n}\\\vdots&\vdots&\ddots&......