首页 > 其他分享 >闲话 23.2.7

闲话 23.2.7

时间:2023-02-07 19:13:19浏览次数:40  
标签:闲话 sum t2 times 23.2 t1 rep mod

闲话

草 感觉写闲话时浑身不自在(
溜了溜了

今日推歌:临川浮梦
链接自行搜吧(
但是好听!

模拟赛题解

感觉最近好颓啊……

T1 神奇纸牌

我怎么写不出容斥式子了?

srds 感觉验题人做法好理解 写验题人的做法(

设颜色种类 \(k = 4\)。我们可以转化成 \(n\times k\) 的网格涂黑,计数联通方案。
考虑每一行 \(k\) 个格子的涂色方案只有 \(2^k\) 种。然后我们可以将方案按出现哪些行涂色方案归类,可以发现只有 \(2^{2^k}\) 种。我们可以暴力筛出来每种行涂色方案是否联通,假设这种方案里有 \(m\) 种行的涂色方案,那贡献就是 \(n\) 个彼此不同的小球放在 \(m\) 个彼此不同的盒子里,每个盒子至少放一个,根据十二重计数法答案显然是 \(\sum_{i\ge 0} (-1)^{m - i} \binom{m}{i} i^n\)。由于 \(m\le 2^k\),可以做到 \(O(2^k \log n)\) 求每种可能。
总时间复杂度 \(O(2^{2^k + 1} + 2^k \log n)\),瓶颈在预处理 \(m\) 对应的方案数。

如果毒瘤出题人把 \(k\) 开到 5,可以预处理每个 \(m\) 有多少种合法方案,打个 \(2^k\) 大小的表,最后只需要 \(O(2^k \log n)\) 统计答案即可。
k 再大还能做吗?

code
#include <bits/stdc++.h>
using namespace std; 
#define int long long
int mod, phi, ans, C[20][20], g[20], cnt[20] = {0,15,95,453,1595,4079,7775,11325,12838,11436,8008,4368,1820,560,120,16,1};
ll n;

int qp(int a, int b) {
    int ret = 1;
    while (b) {
        if (b & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    } return ret;
}

signed main() {
	cin >> n >> mod; 
    rep(i,0,16) C[i][0] = 1;
    rep(i,1,16) rep(j,1,i) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
    rep(i,1,16) g[i] = qp(i, n);
    rep(i,2,16) rep(j,1,i-1) g[i] = (g[i] - 1ll * C[i][j] * g[j] % mod + mod) % mod;
    rep(i,0,16) ans = (ans + 1ll * g[i] * cnt[i]) % mod; 
    cout << ans + 1 << '\n';
}



T2 凌乱平衡树

可以知道 \(\sum dep = \sum size\)。因此我们可以转化成对子树大小之和的求解。

这样转化的好处是只有 treap 一侧的链在合并时的贡献要增加,增加的答案外就是两棵 treap 的字数大小之和,可以每次旋转时 \(O(1)\) 计算。
然后只需要查看增加的贡献。我们拉出来两条边链上节点的 size 自上而下组成的序列,左边 treap 的右链记作 \(A\),右边 treap 的左链记作 \(B\),这两个序列都单减。

观察合并过程。
合并是维护两个初始为 \(1\) 的指针 \(i,j\)。如果 \(A_i \ge B_j\) 则 \(i\) 自增,答案增加 \(B_j\),反之 \(j\) 自增,答案增加 \(A_i\)。
可以发现,\(A_i\) 的贡献次数是落在 \((A_i, A_{i - 1}]\) 里的 \(B\) 的个数,\(B_j\) 的贡献次数是落在 \([B_i, B_{i - 1})\) 里的 \(A\) 的个数。

由于这个相对关系,我们可以让 \(A_i = 2A_i + 1\),\(B_j = 2B_j\),这样就能得到严格的大小关系,好维护了。
可以发现如果将 \(A,B\) 放在值域上,一个值对答案的贡献就是大于它且和他奇偶性不同的极长连续段长度。这个可以用权值线段树上维护连续段得到答案。由于每次旋转只会对边链上 \(O(1)\) 个节点作修改,直接单点修改后维护区间答案,最后提出根节点答案就是增加的答案。

总时间复杂度 \(O(n\log n)\)。

code
#include <bits/stdc++.h>
using namespace std; 
int n, m, t, t1, t2;
ll ans;

struct SegmentBeats {
    #define ls (p << 1)
    #define rs (p << 1 | 1)

    struct node {
        int lmst[2], rmst[2], hd[2], tl[2], cnt;
        ll ans;
        inline friend node operator + (const node& l, const node& r) {
            if (!l.cnt or !r.cnt) return l.cnt ? l : r;
            node ret;
            rep(i,0,1) ret.lmst[i] = l.lmst[i] + (l.lmst[i] == l.cnt ? r.lmst[i] : 0);
            rep(i,0,1) ret.rmst[i] = r.rmst[i] + (r.rmst[i] == r.cnt ? l.rmst[i] : 0);
            rep(i,0,1) ret.hd[i] = l.hd[i] ? l.hd[i] : r.hd[i];
            rep(i,0,1) ret.tl[i] = r.tl[i] ? r.tl[i] : l.tl[i];
            ret.cnt = l.cnt + r.cnt; ret.ans = l.ans + r.ans;
            int bt = r.lmst[0] ? 0 : 1;
            ret.ans += r.lmst[bt] * l.tl[bt ^ 1];
            return ret;
        }
        inline void reset(int typ = -1) { 
            if (typ == -1) memset(this, 0, sizeof *this);
            else lmst[typ] = rmst[typ] = hd[typ] = tl[typ] = 0;
        }
    } seg[N << 3];

    void update(int p, int l, int r, int pos, int va) {
        if (l == r) {
            if (va == -1) seg[p].reset();
            else {
                int bt = pos & 1;
                seg[p].lmst[bt] = seg[p].rmst[bt] = 1;
                seg[p].hd[bt] = seg[p].tl[bt] = pos >> 1;
                seg[p].reset(bt ^ 1); seg[p].cnt = 1, seg[p].ans = 0;
            } return;
        } int mid = l + r >> 1;
        if (pos <= mid) update(ls, l, mid, pos, va);
        else update(rs, mid + 1, r, pos, va);
        seg[p] = seg[ls] + seg[rs];
    }
} Tr;

int rt1, rt2;
struct node {
    int fa, son[2], siz;
} tr[N];

#define ps_p(p) tr[p].siz = tr[tr[p].son[0]].siz + tr[tr[p].son[1]].siz + 1

int vis[N];
void dfs1(int u, bool f) {
    vis[u] = f;
    if (tr[u].son[0]) dfs1(tr[u].son[0], 0);
    if (tr[u].son[1]) dfs1(tr[u].son[1], f);
    ps_p(u); ans += tr[u].siz; 
    if (vis[u]) Tr.update(1, 1, t, tr[u].siz << 1 | 1, 1);
}
void dfs2(int u, bool f) {
    vis[u] = f;
    if (tr[u].son[0]) dfs2(tr[u].son[0], f);
    if (tr[u].son[1]) dfs2(tr[u].son[1], 0);
    ps_p(u); ans += tr[u].siz; 
    if (vis[u]) Tr.update(1, 1, t, tr[u].siz << 1, 1);
}

void rotate1(int u) {
    int f = tr[u].fa, g = tr[f].fa;
    bool sn = tr[f].son[1] == u, fsn = tr[g].son[1] == f;
    if (vis[u]) Tr.update(1, 1, t, tr[u].siz << 1 | 1, -1), vis[f] = 0;
    tr[f].son[sn] = tr[u].son[sn ^ 1], tr[tr[u].son[sn ^ 1]].fa = f;
    ans -= tr[f].siz; ps_p(f); ans += tr[f].siz; 
    tr[u].son[sn ^ 1] = f, tr[f].fa = u;
    ans -= tr[u].siz; ps_p(u); ans += tr[u].siz; 
    if (vis[f]) Tr.update(1, 1, t, tr[f].siz << 1 | 1, 1), vis[u] = 1;
    if (g == 0) rt1 = u, tr[u].fa = 0;
    else tr[g].son[fsn] = u, tr[u].fa = g;
}
void rotate2(int u) {
    int f = tr[u].fa, g = tr[f].fa;
    bool sn = tr[f].son[1] == u, fsn = tr[g].son[1] == f;
    if (vis[u]) Tr.update(1, 1, t, tr[u].siz << 1, -1), vis[f] = 0;
    tr[f].son[sn] = tr[u].son[sn ^ 1], tr[tr[u].son[sn ^ 1]].fa = f;
    ans -= tr[f].siz; ps_p(f); ans += tr[f].siz; 
    tr[u].son[sn ^ 1] = f, tr[f].fa = u;
    ans -= tr[u].siz; ps_p(u); ans += tr[u].siz; 
    if (vis[f]) Tr.update(1, 1, t, tr[f].siz << 1, 1), vis[u] = 1;
    if (g == 0) rt1 = u, tr[u].fa = 0;
    else tr[g].son[fsn] = u, tr[u].fa = g;
}

signed main() {
    cin >> n >> m; t = max(n << 1 | 1, m << 1);
    rep(i,1,n) {
        cin >> t1 >> t2;
        tr[i].son[0] = t1, tr[i].son[1] = t2;
        tr[t1].fa = i, tr[t2].fa = i;
    } rep(i,1,n) if (tr[i].fa == 0) rt1 = i;
    rep(i,n+1,n+m) {
        cin >> t1 >> t2; t1 += (t1 > 0) * n, t2 += (t2 > 0) * n; 
        tr[i].son[0] = t1, tr[i].son[1] = t2;
        tr[t1].fa = i, tr[t2].fa = i;
    } rep(i,n+1,n+m) if (tr[i].fa == 0) rt2 = i;
    dfs1(rt1, 1); dfs2(rt2, 1);
    cout << ans + Tr.seg[1].ans << '\n';
    multi {
        cin >> t1 >> t2;
        if (t1 == 1) rotate1(t2);
        else rotate2(t2 + n);
        cout << ans + Tr.seg[1].ans << '\n';
    }
} 



T3 打扫笛卡尔

说实在的我第一眼以为这是 DS 题(

根据期望线性性,考虑拆解成每个点的答案的加和。然后观察一个深度为 \(d\) 的点。
由于我们计算的是所有可能的 dfs 方法,由祖先向对应方向递归的可能性显然是 \(1/2\),则这个点对答案的期望贡献是 \(d / 2^{d - 1}\)。因此如果记 \(F(i, j)\) 为标号为 \(i\) 的节点深度为 \(j\) 的笛卡尔树的计数,有答案即为

\[\sum_{i\ge 1}\sum_{j\ge 1} F(i, j) \times \frac{j}{2^{j - 1}} \]

我反正不会通过分析得到 \(F\) 的通项,因此考虑 dp 笛卡尔树的形态。设 \(f(i, j)\) 为前 \(i\) 个数里 \(1\to i\) 能拉一条长度为 \(j\) 的左链的排列的计数,我们可以直接分两部分 dp。首先选出 \(i\) 个数来,方案数是组合数。然后前一半的方案数就是 \(2^{j - 1}\times f(i, j)\),考虑到笛卡尔树的链有左右之分。后一半的方案数就是 \((n - i)!\),由于没有限制。也就是

\[F(i, j) = \binom{n}{i} 2^{j - 1} \times f(i, j) \times (n - i)! \]

然后我们就只需要看这条链了。考虑枚举父亲是 \(k\),那 \(\in (k, i)\) 的数不能放在 \(k\sim i\) 之间,而 \(\in [1, k)\) 的可以。可以写出

\[f(i, j) = \sum_{k = 1}^{i - 1}f(k, j - 1)\times \binom{i - 2}{k - 1}\times (i - k - 1)! \]

显然 \(f(1, 1) = 1\)。直接做得到 \(O(n^3)\),前缀和优化 \(O(n^2)\)。

重写答案如下:

\[\sum_{i\ge 1}\sum_{j\ge 1} \binom{n}{i} \times f(i, j) \times (n - i)! \times j \]

听说可以记录 \(g(i, j) = f(i, j)\times j\),然后这两个的前缀和可以不依赖 \(j\) 转移,总时间复杂度能得到 \(O(n)\)。不太懂。

可以发现

\[\sum_{i\ge 1}\sum_{j\ge 1} \binom{n}{i} \times f(i, j) \times (n - i)! \]

即 \(1\to i\) 是一条左链的笛卡尔树的计数。也就是说,任意小于 \(i\) 的数需要在 \(i\) 的右侧,答案就是

\[\sum_{i\ge 0} \binom{n}{i} (i - 1)! (n - i)! = n!\times H_n \]

我们需要的就是一条链的贡献为链长度时的答案。这不太好做,不妨转化链长度为枚举祖先,得到 \(j = 1 + \sum_u [u\ 是\ i\ 的祖先]\)。\(1+\) 的部分如上处理即可,我们现在只需考虑钦定 \(u\) 是 \(i\) 的祖先时如何做上面的计数。

设 \(g(u, i)\) 为 \(1\to i\) 是一条左链且 \(u\) 在其上的笛卡尔树的计数,可以知道这部分的答案就是 \(\sum_{i} \sum_{u < i} g(u, i)\)。我们仍然可以做如上的划分值域限制的讨论,能得到 \(\in [1, u)\) 的数只能在 \(u\) 的右侧,\(\in (u, i)\) 的数只能在 \(i\) 的右侧,其余的数随意。作计数就是

\[g(u, i) = \binom{n}{i}(n - i)! \binom{i - 1}{u} (i - u - 1)! (u - 1)! = \frac{n}{ui} \]

这部分的答案就是

\[n! \sum_{i\ge 0} H_{i - 1} \]

可以将 \(n!\) 乘进去,第一部分部分是前缀积乘后缀积的形式,而这一部分可以记录一个积之和,算 \(i\) 的答案乘入后缀积,然后加一个 \(i - 1\) 位置的前缀积即可。

总时间复杂度 \(O(n)\)。

code
#include <bits/stdc++.h>
using namespace std; 
int n, ans, sum, mod, prf[N], suf[N];

signed main() {
    iot; file(cartesian);
	cin >> n >> mod; 
    prf[0] = suf[n + 1] = 1;
    rep(i,1,n) prf[i] = 1ll * prf[i - 1] * i % mod;
    pre(i,n,1) suf[i] = 1ll * suf[i + 1] * i % mod;
    rep(i,1,n) {
        ans = (ans + 1ll * prf[i - 1] * suf[i + 1]) % mod;
        ans = (ans + 1ll * sum * suf[i + 1]) % mod;
        sum = (1ll * sum * i + prf[i - 1]) % mod;
    } cout << ans << '\n';
} 

标签:闲话,sum,t2,times,23.2,t1,rep,mod
From: https://www.cnblogs.com/joke3579/p/chitchat230207.html

相关文章

  • 闲话 23.2.6
    闲话?感觉没啥想说的诶但是jjdw请勿宣称一些不存在的辈分关系......
  • 2023.2.6 日寄
    2023.2.6日寄一言\(~~~~\)人生海海,潮落之后是潮起。你说那是消磨、笑柄、罪过,可那就是我的英雄主义。——麦家模拟赛ClickHere鲜花\(~~~~\)今天和同学去食......
  • 闲话收集
    一些闲话。没有文学水平,是且仅是记录当时的感情或者是生活。从新到旧排序,一些太垃圾的就没有从洛谷搬过来。我画出奇怪的梦洗内裤了Whureereyoaexpedition吵死了......
  • web之php一句话木马总结------2023.2.6
    一句话木马的原理<?php@eval($_POST['shell']);?>这是php的一句话后门中最普遍的一种。它的工作原理是:首先存在一个名为shell的变量,shell的取值为HTTP的POST方式。Web......
  • web之命令执行常见函数------2023.2.6
     system()函数作用:将字符串作为OS命令执行,自带输出功能。格式:stringsystem(string$command[,int&$return_var])//$command为执行的命令,&return_var可选,用来......
  • 2023.2.5
    Generic(泛型)用泛型来指定集合中存储的数据类型使用泛型的好处1.集合中存储的元素类型统一了2.从集合中取出的元素类型是泛型指定的类型,不用更多的向下转型泛型的......
  • 技术规划与产品路标开发实践(2023.2.17~18,深圳)
    【课程背景】技术规划流程TPP(TechnologyPlanningProcess),就是根据业务和市场目标进行所需技术的识别和分析,并给出相应的策略的过程。技术规划的根本目标是让产品在市场竞......
  • CSS 3 所有的选择器整理(2023.2)
    你知道的和你不知道的所有选择器。不包含尚未广泛实现的,也不包含已弃用的。基本的选择器规则(Selector)类型(Type)选择器直接用标签匹配特定的元素span{ ...}p{ .........
  • 2023.2.5 日寄
    2023.2.5日寄一言\(~~~~\)所有随风而逝的都是属于昨天的,所有历经风雨留下来的才是面向未来的。——《飘》模拟赛ClickHere鲜花\(~~~~\)哪有那么多鲜花啊。不......
  • 利用for与if嵌套句式来寻找质数——2023.2.5
    #include<stdio.h>intmain(void){/*局部变量定义*/inti,j;for(i=2;i<100;i++){for(j=2;j<=(i/j);j++)......