首页 > 其他分享 >10 月 15 日模拟赛总结

10 月 15 日模拟赛总结

时间:2023-10-15 23:22:52浏览次数:36  
标签:10 le 15 int res ll kMaxN 模拟

Before

本文章在洛谷博客同步发布

Contest-Link

预期 \(30 + 0 + 0 + 20 = 50\)。

实际 \(30 + 0 +100+ 60 = 190\)。

挂分 \(-140\)。

rk6,行。

开题首先瞄了眼 T1,想 dp 感觉挺玄乎,写了个暴力,跳 T2 发现什么鬼题面,直接跳 T3,感觉 T3 可做,维护区间 \(1\) 的个数不直接用线段树?写了个线段树对拍没过!非常愤怒。非常愤怒。非常愤怒。结果是暴力写错了哈哈,然后手推了一下发现没啥问题,看 T4,\(n \le 200\) 我直接打表,发现时间不够了写了个爆搜跑路。

然后就寄了。

T1

Description

求 \(\max^n_{i=1}\{\max^i_{j=1}a_i\times\min^i_{j=1}a_i\times i\}\)。

\(1 \le n\le 2\times 10^6,1\le a_i \le 10^9\)。

Solution

显然,我们需要枚举最小值找最大值,然后这一部分可以用一个神奇的思路:用并查集贪心。大致是按降序枚举每一条边,并查集维护连通块来算贡献。

具体来说,我们将 \(a\) 抽象成一条 \(n+1\) 个点,\(n\) 条边的链,每条边的边权为 \(a_i\),同时建一个并查集,记录每个分开的数列的大小。

我们考虑要在这个上面找到一个最大的区间使得当前枚举的最小值仍然等于区间的最小值,简单来说就是找到一个最大的区间使得最小值不变。由于区间最大,答案也相应在最小值不变的情况下最大化了。

考虑按照权大小从大到小选择,对于一个点,被选择时所在连通块就表示它的合法最大区间,最后并查集上维护最大值和区间大小即可。

为什么这样贪心一定是对的呢?

因为我们按权降序排序,选择一个边时,过这条边的每条路径的最小边权都由这条边贡献

好像正解是 ST 表 + 单调栈,听起来很高级的样子。

考场想法:暴力。

考场寄因:暴力。

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

Code

\(\text{100pts:}\)

// 2023/10/15 PikachuQAQ

#include <iostream>
#include <algorithm>

using namespace std;

typedef __int128 B;
typedef long long ll;

const int kMaxN = 2e6 + 7;

struct S { 
    int id;
    ll res;
    friend bool operator < (const S& a, const S& b) {
        return a.res > b.res;
    }
} b[kMaxN];

ll n, a[kMaxN];
B ans, maxn[kMaxN];
int fa[kMaxN], siz[kMaxN];
bool vis[kMaxN];

int findfa(int x) {
    return (fa[x] == x) ? x : (fa[x] = findfa(fa[x]));
}

void uni(int x) {
    vis[x] = 1;
    for (int i = -1, u, v; i <= 1; i += 2) {
        if (vis[x + i]) {
            u = findfa(x), v = findfa(x + i);
            maxn[u] = max(maxn[u], maxn[v]);
            fa[v] = u, siz[u] += siz[v];
        }
    }
}

void init() {
    for (int i = 1; i <= n; i++) {
        fa[i] = i, siz[i] = 1;
        maxn[i] = b[i].res = a[i], b[i].id = i;
    }
}

void write(B x) {
    if (x == 0) {
        return;
    }
    write(x / 10), putchar(x % 10 + 48);
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    if (n == 1) {
        int x;
        cin >> x;
        cout << x;
        return 0;
    }
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    init(), sort(b + 1, b + n + 1);
    for (int i = 1, x = 0; i <= n; i = x, i++) {
        x = i, uni(b[i].id);
        while (b[i].res == b[x + 1].res) {
            x++, uni(b[x].id);
        }
        for (int j = i, p; j <= x; j++) {
            p = findfa(b[j].id), ans = max(ans, (B)b[j].res * siz[p]);
        }
    }
    write(ans);

    return 0;
}

T2

Description

给定正整数 \(n\),计算 \(n\) 个元素的集合 \(\{1, 2, \cdots, n\}\),所有非空子集的乘积取模 \(998244353\) 后的结果。

\(1 \le n \le 200\)。

Solution

定义函数 \(g(i)\) 为求子集每种和的方案数。

注意到 \(1 \le n \le 200\),发现这里比较像 01 背包的模型:将 \(a_i\) 看作物品,花费为 \(i\),价值为 \(f_{j-i}\)。于是我们可以跑背包。

则答案是:

\[\prod^{n(n+1)}_{i=1}i^{g(i)} \]

考虑质数取模,根据费马小定理,有 \(S\equiv \text{ans}(\bmod \text{ }p-1)\),其中 \(S\) 为答案式子,\(\text{ans}\) 为答案,\(p\) 为取模的质数。

考场想法:爆搜。

考场寄因:爆搜。

时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\)。

Code

\(\text{100pts:}\)

// 2023/10/15 PikachuQAQ

#include <iostream>

using namespace std;

typedef long long ll;

const int kMaxN = 60007, mod = 998244353;

ll f[kMaxN], n, ans = 1;

ll qpow(ll a, ll b, ll mod) {
    ll res;
    for (res = 1; b; a = a * a % mod, b >>= 1) {
        if (b & 1) {
            res = res * a % mod;
        }
    }
	return res % mod;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n, f[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = i * (i + 1) / 2; j >= i; j--) {
            f[j] += f[j - i] % (mod - 1);
        }
    }
    for (int i = 1; i <= n * (n + 1) / 2; i++) {
        ans *= qpow(i, f[i], mod), ans %= mod;
    }
    cout << ans % mod;

    return 0;
} 

T3

Description

长度为 \(n\) 的只包含 \(0\) 和 \(1\) 的序列,你可以对它进行多次操作。在每次操作中,你都可以选择一个数字 \(0\) 变成 \(1\),或者选择一个数字 \(1\) 变成 \(0\),使得最终局面满足如下特点:对于任意相邻的两个 \(1\).它们在序列中的距离都是 \(d\) 的倍数,给定 \(d\),求最小操作次数。长度为 \(n\) 的只包含 \(0\) 和 \(1\) 的序列,每次操作选一个 \(0\) 变 \(1\) 或者 \(1\) 变 \(0\),使得最终局面的相邻的两个 \(1\) 之间距离是 \(d\) 的倍数,问最小操作次数。

\(1 \le n \le 2\times 10^5\)。

Solution

对于第一个操作,可以证明只有第二个操作(\(1\) 变 \(0\))是最优的,第一个操作(\(0\) 变 \(1\))用于将数列置为 \(0\),只会有一种方案,最后计算用到。

首先,题面说到距离可以是 \(d\) 的倍数,这里我们一定选 \(d\),因为当距离越大,\([i,i+d]\) 的 \(1\) 的个数就会更多,相对于更小的 \(d\) 来说并不利。

然后,我们枚举起始位置 \([1, d]\),然后枚举 \(i-d+1\) 和 \(i-1\),也就是不是 \(d\) 倍数的区间,找其中 \(1\) 需要置为 \(0\) 的个数,这一部分可以用线段树(不是可以直接前缀和吗?)维护,然后把所有不是 \(d\) 倍数的位置上的 \(1\) 的贡献(就是 \(1\))加起来即可。

最后和之前说的将数列置为全 \(0\) 的贡献取 \(\min\) 即可。

考场想法:线段树。

考场寄因:没寄。

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

Code

\(\text{100pts:}\)

// 2023/10/15 PikachuQAQ

#include <iostream>

using namespace std;

const int kMaxN = 2e5 + 7, kMaxM = 8e5 + 7;

typedef long long ll;

ll seg[kMaxM], add[kMaxM];
int n, d, a[kMaxN], ans, res;

int M(int l, int r) { return l + r >> 1; } 
int L(int p) { return p << 1; } 
int R(int p) { return p << 1 | 1; } 
void tag(int l, int r, int p, ll d) { add[p] += d, seg[p] += (r - l + 1) * d; } 
void pushup(int p) { seg[p] = seg[L(p)] + seg[R(p)]; }
void pushdown(int l, int r, int p) { 
    tag(l, M(l, r), L(p), add[p]), tag(M(l, r) + 1, r, R(p), add[p]);
    add[p] = 0;
}

void Build(int l, int r, int p) {
    if (l == r) {
        seg[p] = a[l];
    } else {
        Build(l, M(l, r), L(p)), Build(M(l, r) + 1, r, R(p)), pushup(p);
    }
}

void Update(int s, int t, int l, int r, int p, ll d) {
    if (s <= l && r <= t) {
        tag(l, r, p, d);
    } else {
        pushdown(l, r, p);
        if (s <= M(l, r)) {
            Update(s, t, l, M(l, r), L(p), d);
        }
        if (t >= M(l, r) + 1) {
            Update(s, t, M(l, r) + 1, r, R(p), d);
        }
        pushup(p);        
    }
}


ll Query(int s, int t, int l, int r, int p) {
    ll res = 0;
    if (s <= l && r <= t) {
        return seg[p];
    }
    pushdown(l, r, p);
    if (s <= M(l, r)) {
        res += Query(s, t, l, M(l, r), L(p));
    } 
    if (t >= M(l, r) + 1) {
        res += Query(s, t, M(l, r) + 1, r, R(p));
    }
    return res;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> d;
    Build(0, n + d, 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        ans += a[i];
        Update(i, i, 0, n + d, 1, a[i]);
    }
    if (ans == 0) {
        cout << 0 << '\n';
        return 0;
    }
    ans--;
    for (int i = 1; i <= d; i++) {
        for (int j = i, x = 0; j <= n + d; j += d) {
            x = max(0, j - d + 1);
            res += Query(x, j - 1, 0, n + d, 1);
        }
        ans = min(ans, res), res = 0;
    }
    cout << ans; 

    return 0;
}

T4

Description

啊?

Solution

啊?

Code

啊?

Summary

需要掌握的:?

标签:10,le,15,int,res,ll,kMaxN,模拟
From: https://www.cnblogs.com/PikachuQAQ/p/10-15-contest-ji-yin.html

相关文章

  • 2023.10.15——每日总结
    学习所花时间(包括上课):9h代码量(行):0行博客量(篇):1篇今天,上午休息,下午校内算法比赛;我了解到的知识点:1.写对四道;明日计划:学习......
  • 2023-10-15 #73 就等待吧
    ——COP《雪来临时》如题,所以抱歉这次鸽了。511P8354[SDOI/SXOI2022]多边形三角剖分是我们已解决的经典问题,答案是卡特兰数。我们尝试通过一些手段去除题目中的限制,求出系数\(c_3,c_4,\cdots,c_m\),将问题规约至求若干次多边形的三角剖分数量,最后答案为\(\sum_ic_i\text{C......
  • 2023-2024-1 20231310《计算机基础与程序设计》第三周学习总结
    作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP/homework/12999这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK03这个作业的目标计算机科学概论第2、3章,《C语言程序设计》第2章并完成云班课测试......
  • 2023-2024-1 20231415《计算机基础与程序设计》第三周学习总结
    这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK03这个作用的目标学习计算机科学概论第2章第3章和《C语言程序设计》第2章,并完成作业要求作业正文https://i.cn......
  • 2023-2024-1 学号20231315第三周学习总结
    学期:2023-2024-1学号:20231315《计算机基础与程序设计》第二周学习总结作业信息这个作业属于哪个课程2023-2024-1《计算机基础与程序设计》这个作业要求在哪里2023-2024-1《计算机基础与程序设计》这个作业的目标学习计算机科学概论第2章第3章和《C语言程序设计......
  • 一周总结(2023.10.2-2023.10.15)
    2023.10.2考试。T1是简单的,T2是一个比较简单的dp,状态等东西都是对的,但是因为有一个地方没有取模而只交了暴力。受不鸟。T3是概率dp,考场上想了比较久想出来并实现了。T4是一个容斥计数题,大概理解了但是没有补。考场上千万要注意细节,以免丢掉不该丢的分。2023.10.3还是考试......
  • 文心一言 VS 讯飞星火 VS chatgpt (113)-- 算法导论10.2 5题
    五、用go语言,使用单向循环链表实现字典操作INSERT、DELETE和SEARCH,并给出所写过程的运行时间。文心一言:在Go语言中,我们首先需要定义一个Node结构体来表示单向循环链表的节点,然后再定义一个LinkedList结构体来表示单向循环链表。接下来,我们可以实现INSERT、DELETE和SEARCH操作。......
  • 文心一言 VS 讯飞星火 VS chatgpt (113)-- 算法导论10.2 5题
    五、用go语言,使用单向循环链表实现字典操作INSERT、DELETE和SEARCH,并给出所写过程的运行时间。文心一言:在Go语言中,我们首先需要定义一个Node结构体来表示单向循环链表的节点,然后再定义一个LinkedList结构体来表示单向循环链表。接下来,我们可以实现INSERT、DELETE和SEARCH操作......
  • P3177 [HAOI2015] 树上染色
    P3177[HAOI2015]树上染色[P3177HAOI2015]树上染色-洛谷|计算机科学教育新生态(luogu.com.cn)目录P3177[HAOI2015]树上染色题目大意思路code题目大意有一棵\(n\)个点的树,你可以在上面把\(k\)个点染成黑色,收益为黑点两两之间的距离和加上白点两两之间的距离和求......
  • 模拟集成电路设计系列博客——2.4.2 全差分折叠Cascode放大器
    2.4.2全差分折叠Cascode放大器下图展示了一个简化的全差分折叠Cascode放大器。使用两个Cascode电流源来取代之前介绍的结构中的n沟道电流镜,并增加了一个共模反馈电路。这些电流源的驱动晶体管的栅压由共模反馈电路的输出电压\(V_{cntrl}\)决定。共模反馈电路的输入是全差分放大......