[题解]嘉然今天晚上吃点好的

校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?The principal is really a godwith a closestool on the left and Yongshen on the rightholding a sharp pen to pierce the truthWho can resist him? 校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? Le principal est vraiment un dieuavec des toilettes à gauche et Yongshen à droitetenant un stylo pointu pour percer la véritéQui peut lui résister ? Der Direktor ist wirklich ein Gottmit einer Toilette links und Yongshen rechtsder einen spitzen Stift hältum die Wahrheit zu durchdringen.Wer kann ihm widerstehen? Principalis deus est, Yongshen a dextris cum latrinaacuto stylo ad perforandum veritatem: quis resistet ei? 对曰:“无人,狗欲当之,还请赐教!”




  BackToTheMenu.

2022-03-03 嘉然今天晚上吃点好的

  本来只给第二题分配了一个半小时,结果一直调到考试结束......

矩形 / Rectangle

  建笛卡尔树,然后想怎么搞怎么搞。

/** @author __Elaina__ */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
template<class T> inline void myswap(T& x, T& y) { x ^= y ^= x ^= y; }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 1e5;
const int Mod = 1e9 + 7;
const int inv2 = 500000004;
inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

int h[Maxn + 5], w[Maxn + 5], n;

inline void input() {
    readin(n);
    rep (i, 1, n) readin(h[i]);
    rep (i, 1, n) readin(w[i]);
}

int lson[Maxn + 5], rson[Maxn + 5];
int stk[Maxn + 5], tl;
inline void buildTree() {
    rep (i, 1, n) {
        while (tl && h[stk[tl]] >= h[i]) lson[i] = stk[tl--];
        if (stk[tl]) rson[stk[tl]] = i;
        stk[++tl] = i;
    }
}

int f[Maxn + 5];
void dfs(int u) {
    if (lson[u]) dfs(lson[u]), chkadd(f[u], f[lson[u]]);
    if (rson[u]) dfs(rson[u]), chkadd(f[u], f[rson[u]]);
    int tmp = 1ll * h[u] * (h[u] + 1) % Mod * inv2 % Mod;
    if (lson[u]) chkadd(f[u], 1ll * w[lson[u]] * w[u] % Mod * tmp % Mod);
    if (rson[u]) chkadd(f[u], 1ll * w[rson[u]] * w[u] % Mod * tmp % Mod);
    if (lson[u] && rson[u])
        chkadd(f[u], 1ll * w[lson[u]] * w[rson[u]] % Mod * tmp % Mod);
    chkadd(f[u], 1ll * w[u] * (w[u] + 1) % Mod * inv2 % Mod * tmp % Mod);
    chkadd(w[u], (w[lson[u]] + w[rson[u]]) % Mod);
}

signed main() {
    freopen("rectangle.in", "r", stdin);
    freopen("rectangle.out", "w", stdout);
    input();
    buildTree();
    dfs(stk[1]);
    writln(f[stk[1]]);
    return 0;
}

[CEOI2020]星际迷航 / Tree

  虽然一看就是矩阵加速......

  如果 D=0(虽然没有),就是一个很明显的 DP 了,可以设 sg(i) 表示 i 点的 SG 函数值,那么有转移

sg(u)=vson(u)(sg(v)1)

  当 D=1,有了一个副本,而通过传送门走到下一个副本的点 x,实际上就是以 x 为根做上面的东西,因此很明显我们需要换根。

  有了上面的铺垫,你会发现接一个传送门,实际上是给原来的树上的某个点接上一个 sg0 或者 1 的儿子,而该儿子在下一个副本将被视为根,也就是说,我们实际上关注的重点始终都是副本的根的状态,而不在意当点不为根时的状态,所以我们可以设计一个状态:f(i,0/1) 表示考虑到副本 i,使得根的状态最终为 0/1 的方案数。

  显然,求出初始的 f(D,0/1) 需要我们实现一个换根 DP,而从一个副本转移到另外一个副本呢?

  由于 “接一个传送门,实际上是给原来的树上的某个点接上一个 sg0 或者 1 的儿子”,而根据上面的 sg 转移,又发现接上一个 sg=1 的儿子好像对整棵树没啥影响,但是接上一个为 0 的儿子,对其父亲,乃至根可能都有影响。因此,我们对于转移有了一个大概的思路,先对当前的点最终状态是 0 还是 1 进行分类,假如当前的点最终是 0,那么有两种情况:本身就是 0,或者本来是 1,但是树中的某个点翻转之后影响到它了,设 sg(u) 表示没有进行任何修改时,点 usg 函数值,那么就有

f(i,0)=sg(u)=1flip(u)×f(i+1,0)+sg(u)=0n×f(i+1,1)=Fp(1)×f(i+1,0)+n×loss×f(i+1,1)

  其中 flip(u) 为当 u 是根时,有多少原必败点翻转后会影响到它(你无法让必胜点翻转),而 Fp(t)=sg(u)=tflip(u)loss=[sg(u)=0],同样,我们可以发现 f(i,1) 的转移:

f(i,1)=sg(u)=0flip(u)×f(i+1,0)+sg(u)=1n×f(i+1,1)=Fp(0)×f(i+1,0)+n×win×f(i+1,1)

  其中 win 的定义和 loss 相反。

  不难发现,转移中 Fp(),n,win,loss 这些系数都是固定的,因此可以直接矩阵加速转移,时间复杂度 O(n+log2D×23).

  因为找不到草稿纸了所以不知道转移是否写错了,如有写错请指出。

/** @author __Elaina__ */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
template<class T> inline void myswap(T& x, T& y) { x ^= y ^= x ^= y; }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

// #define int long long

const int Mod = 1e9 + 7;
const int Maxn = 1e5;
inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

int n; ll D;
vector<int> g[Maxn + 5];

struct matrix {
    int c[2][2];
    inline matrix() { memset(c, 0, sizeof c); }
    inline matrix operator *(const matrix& rhs) {
        matrix ret;
        for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j)
            for (int k = 0; k < 2; ++k)
                chkadd(ret.c[i][k], 1ll * c[i][j] * rhs.c[j][k] % Mod);
        return ret;
    }
    inline void print() {
        for (int i = 0; i < 2; ++i) {
            for (int j = 0; j < 2; ++j)
                writln(c[i][j], ' ');
            Endl;
        }
    }
};
inline matrix qkpow(matrix a, ll q) {
    matrix ret;
    for (int i = 0; i < 2; ++i) ret.c[i][i] = 1;
    for (; q; q >>= 1, a = a * a) if (q & 1) ret = ret * a;
    return ret;
}

inline void input() {
    readin(n, D);
    int u, v;
    rep (i, 2, n) {
        readin(u, v);
        g[u].push_back(v), g[v].push_back(u);
    }
}

int sg[Maxn + 5], cnt[Maxn + 5][2];
int dp[Maxn + 5][2]; ///< sum[][1] is for all
int flip[Maxn + 5];
inline void update(int u) {
    flip[u] = 0;
    if (sg[u]) {
        if (cnt[u][0] == 1) flip[u] = dp[u][0];
    }
    else flip[u] = dp[u][1]; // flip a son can change everything
}
void dfs1(int u, int par) {
    for (const int& v: g[u]) if (v ^ par)
        dfs1(v, u), ++cnt[u][sg[v]];
    sg[u] = !!cnt[u][0];
    for (const int& v: g[u]) if (v ^ par) {
        dp[u][1] += flip[v] + (!sg[v]);
        if (!sg[v]) dp[u][0] += flip[v] + 1;
    }
    update(u);
}

int sum[2], win;
void dfs2(int u, int par) {
    int _sg, _fli, _cnt[2], _dp[2];
    _sg = sg[u], _fli = flip[u];
    memcpy(_cnt, cnt[u], sizeof _cnt);
    memcpy(_dp, dp[u], sizeof _dp);
    win += _sg, chkadd(sum[_sg], _fli);

    if (!_sg) chkadd(sum[_sg], 1);
    for (const int& v: g[u]) if (v ^ par) {
        --cnt[u][sg[v]];
        if (!sg[v]) dp[u][0] -= flip[v] + 1;
        dp[u][1] -= flip[v] + (!sg[v]);
        sg[u] = !!cnt[u][0];
        update(u);

        ++cnt[v][sg[u]];
        if (!sg[u]) dp[v][0] += flip[u] + 1;
        dp[v][1] += flip[u] + (!sg[u]);
        sg[v] = !!cnt[v][0];
        update(v);

        dfs2(v, u);

        sg[u] = _sg, flip[u] = _fli;
        memcpy(cnt[u], _cnt, sizeof _cnt);
        memcpy(dp[u], _dp, sizeof _dp);
    }
}

matrix acc, a;

signed main() {
    // freopen("tree.in", "r", stdin);
    // freopen("tree.out", "w", stdout);
    input();
    dfs1(1, 0);
    dfs2(1, 0);
    // fprintf(stderr, "sum[0] == %d, sum[1] == %d\n", sum[0], sum[1]);
    // fprintf(stderr, "win == %d\n", win);
    acc.c[0][0] = (1ll * (n - win) * n % Mod + Mod - sum[0] + sum[1]) % Mod;
    acc.c[0][1] = 1ll * (n - win) * n % Mod;
    acc.c[1][1] = 1ll * win * n % Mod;
    acc.c[1][0] = (1ll * win * n % Mod + Mod - sum[1] + sum[0]) % Mod;
    // acc.print();
    a.c[0][0] = n - win, a.c[1][0] = win;
    a = qkpow(acc, D - 1) * a;
    // a.print();
    int t0 = a.c[0][0], t1 = a.c[1][0], ans = 0;
    if (sg[1])
        ans = (1ll * (n - flip[1]) * (t0 + t1) % Mod + 1ll * flip[1] * t1 % Mod) % Mod;
    else ans = 1ll * (flip[1] + 1) * t0 % Mod;
    writln(ans);
    return 0;
}
/**
 * 
 * @p D is too large -> use matrix to accelerate DP transfer
 * 
 * When @p D == 0, tree DP is enough
 *      sg(u) = \Or_{v is the son of u} (sg(v) ^ 1)
 * 
 * When @p D == 1
 *      root-changing DP?
 *      regard the first node we reach on the second tree as the root
 *      and run the game
 * 
 * pay attention to that "root" is the key
 * the only thing that we need to care about is the value of sg() of the root
 * 
 * define f(i, s):
 *      the number of ways
 *      to make the root of tree @p i satisfy sg(root) = @p s
 * 
 * a question that some points' changing may affect the state of root
 * use root-changing DP to solve it!
 * 
*/

排序 / Sort

  这个题实际上和 <2022-02-26 可恶!然而......:排队 / Queue> 是一样的,因为,存在这样一个等式......

12i=1n|ipi|=i=1nmax(ipi,0)

  因此,需要满足的结论也应当是一样的,即 max(ipi,0)=d(i),然后就有个同样的结论:要么前面没有比它大的(i<pi),要么比它小的全在它前面(i>pi),然后设计 DP 状态,f(i,j) 表示当前位置是 i,前面的数字集合的最大值为 j 时的方案数,那么有

f(i,j)=f(i1,j)+k<jf(i1,k)

  同样的前缀和,就有

g(i,j)=g(i1,j)+g(i,j1)g(0,0)=1

  看似又归约到卡塔兰数的问题上,但是有个问题:如何比较字典序?实际上很简单,用类似数位 DP 的方法做即可,即我们每次贴近一个前缀,然后统计从枚举的这个位置 i 开始 “出超” 的方案数,因为 “出超” 之后就不受 p 的限制而只受 y=x 的限制,因此可以直接用卡塔兰数来算,实际上和 <排队> 是一样的,钦定前缀进行计算。时间复杂度 O(n).

/** @author __Elaina__ */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
template<class T> inline void myswap(T& x, T& y) { x ^= y ^= x ^= y; }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Mod = 998244353;
const int Maxn = 2000000;

inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

int fac[Maxn + 5], inv[Maxn + 5], finv[Maxn + 5];
inline void prelude() {
    fac[0] = fac[1] = inv[0] = inv[1] = finv[0] = finv[1] = 1;
    rep (i, 2, Maxn) {
        fac[i] = 1ll * fac[i - 1] * i % Mod;
        inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;
        finv[i] = 1ll * finv[i - 1] * inv[i] % Mod;
    }
}
inline int C(int n, int m) {
    if (n < m || n < 0 || m < 0) return 0;
    return 1ll * fac[n] * finv[n - m] % Mod * finv[m] % Mod;
}
inline int cata(int n, int m) {
    return (C(n + m, m) + Mod - C(n + m, m - 1)) % Mod;
}

int p[Maxn + 5], n;
bool used[Maxn + 5];

inline void solve() {
    readin(n);
    rep (i, 1, n) readin(p[i]);
    int mex = 1, mx = 0, ans = 0;
    memset(used + 1, false, n);
    rep (i, 1, n) {
        int y = max(mx + 1, p[i] + 1);
        used[p[i]] = true;
        if (y <= n) chkadd(ans, cata(n - i + 1, n - y));
        if (mx < p[i]) mx = p[i];
        else if (p[i] != mex) break;
        while (used[mex]) ++mex;
    }
    writln(ans);
}

signed main() {
    freopen("sort.in", "r", stdin);
    freopen("sort.out", "w", stdout);
    prelude();
    rep (_, 1, readret(1)) solve();
    return 0;
}
posted @   Arextre  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2020-03-14 「模板」替罪羊树
点击右上角即可分享
微信分享提示