码迷,mamicode.com
首页 > 其他好文 > 详细

【UOJ424】count

时间:2020-01-16 18:51:01      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:直接   class   stream   笛卡尔   return   algorithm   ++   节点   print   

题面

UOJ

题解

\(m>n\)显然无解。

建出这个序列的笛卡尔树(如果大小相同则取最左的点),那么一颗笛卡尔数对应且只对应一种序列。

考虑这棵笛卡尔树的性质,就是往左儿子走它的数的大小必然减小至少\(1\),而往右走是不一定减一的。

那么这棵笛卡尔树必须要满足从根往叶子节点走,向左走的次数\(\leq m\)

考虑这个笛卡尔树的括号序列,就是说一个点每往左走就打一个(然后回溯回来就打一个),向右儿子走则不管,注意一个点如果没有左儿子的话就直接上一个()

设‘(‘权值为\(1\),‘)‘权值为\(-1\),那么这个括号序列需要满足的要求有:\(0\leq\)前缀和\(\leq m\)

将这个转成格路问题,就是从\((0,0)\)走整点到\((n,n)\),其中每一步只能向右或向上走一格,且不能碰到直线\(A:y=x+1,B:y=x-m-1\),问方案数。

将连续碰到一条直线看作一次碰撞(例如\(ABBAAB\)看作\(ABAB\)),那么可以枚举一次碰到什么直线,容斥计数即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
#include <tuple>
using namespace std; 
const int Mod = 998244353; 
const int MAX_N = 2e5 + 5; 
int fpow(int x, int y) { 
    int res = 1; 
    while (y) { 
        if (y & 1) res = 1ll * res * x % Mod; 
        x = 1ll * x * x % Mod; 
        y >>= 1; 
    } 
    return res; 
} 
int N = 2e5, M, fac[MAX_N], ifc[MAX_N]; 
int C(int n, int m) { 
    if (n < 0 || m < 0 || n < m) return 0; 
    else return 1ll * fac[n] * ifc[m] % Mod * ifc[n - m] % Mod; 
} 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    fac[0] = 1; for (int i = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % Mod; 
    ifc[N] = fpow(fac[N], Mod - 2); 
    for (int i = N - 1; ~i; i--) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % Mod; 
    cin >> N >> M;
    if (M > N) return puts("0") & 0; 
    int x = N, y = N, ans = C(x + y, x); 
    while (x >= 0 && y >= 0) { 
        tie(x, y) = make_tuple(y - 1, x + 1), ans = (ans - C(x + y, x) + Mod) % Mod; 
        tie(x, y) = make_tuple(y + M + 1, x - M - 1), ans = (ans + C(x + y, x)) % Mod; 
    } 
    x = y = N;
    while (x >= 0 && y >= 0) { 
        tie(x, y) = make_tuple(y + M + 1, x - M - 1), ans = (ans - C(x + y, x) + Mod) % Mod; 
        tie(x, y) = make_tuple(y - 1, x + 1), ans = (ans + C(x + y, x)) % Mod; 
    } 
    printf("%d\n", ans); 
    return 0; 
} 

【UOJ424】count

标签:直接   class   stream   笛卡尔   return   algorithm   ++   节点   print   

原文地址:https://www.cnblogs.com/heyujun/p/12202399.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!