首页 > 其他分享 >2023QDEZ男人八题线上同步赛 赛时代码和思路

2023QDEZ男人八题线上同步赛 赛时代码和思路

时间:2023-10-31 10:25:18浏览次数:45  
标签:2023QDEZ return 赛时 rr int res ll vi 八题

2023QDEZ男人八题线上同步赛 赛时代码和思路

比赛链接赛时答疑洛谷博客

\(\texttt{A-std}\)\(\texttt{B-std}\)\(\texttt{C-std}\)\(\texttt{D-std}\)\(\texttt{E-std}\)\(\texttt{F-std}\)\(\texttt{G-std}\)\(\texttt{H-std}\)\(\texttt{Ex-std}\)

我:\(50+50+20+5+30+45+0+0+0=200\text{pts}\).

喜提二中比赛除了二中选手以外的 rk1(大雾

以下是赛时代码和思路,省略快读和头文件等。

PS:因为博客太长了不好看,所以可能把源代码里的空行删去了。

前置代码说明:

#include <bits/stdc++.h>
using namespace std;
#define rep(i, x) for (int i = 0; i < (x); ++i)
#define rr read()
inline int read() { // 有的时候换成了 long long
    int num = 0, flag = 1, ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
    for (; isdigit(ch); ch = getchar()) num = num * 10 + ch - '0';
    return num * flag;
}

T1

一个数减 \(k\) 次一,每次操作对答案的贡献为,最后面一个 \(1\) 是倒数第几个数。

先打暴力!

void solve(ll n, ll k) {
    ll res = 0; while (k--)  {
        auto t = n; --n, ++res;
        ll kk = 1;
        while ((t & 1) == 0) ++res, t >>= 1, ++kk;
        cerr << n + 1 << " - " << n << ": " << kk << endl;
    } printf("%lld\n", res);
} signed main() {
    int T = rr; while (T--) {
        ll n = rr, k = rr; solve(n, k);
    } return 0;
}

然后想想,\(10^{18}\),在我的知识范围内,除了数学大概也只有数学加持的动规了。

咋数学呢?先查分吧,好想。

就是 \(f(r)-f(l-1)\) 然后 \(f(x)\) 怎么算。

然后发现从后面一位一位的看,倒数第 \(i\) 位的 \(1\) 似乎需要 \(2^i\) 次 \(-1\) 操作才能消掉。

发现规律,解决!

ll solve(ll x) {
    ll res = 0;
    while (x) res += x, x >>= 1;
    return res;
} signed main() {
    int T = rr; while (T--) {
        ll n = rr, k = rr;
        if (n == k) printf("%lld\n", solve(n));
        else printf("%lld\n", solve(n) - solve(n - k));
    } return 0;
}

T2

求本质不同的子序列个数。

题目背景说了是动规,干嘛不想想是不是动规。

想不到,先打暴力。

using ll = long long;
using vi = vector<int>;
const ll MOD = 998244353;
int n; vi a;
set<pair<int, vi>> mem;
ll cnt = 0; void dfs(int k, vi now) {
    if (mem.count({k, now})) return;
    mem.insert({k, now});
    if (k == n) { cnt = (cnt + 1) % MOD; return; }
    dfs(k + 1, now); now.push_back(a[k]);
    dfs(k + 1, now);
} signed main() {
    n = rr; rep(i, n) a.push_back(rr);
    dfs(0, vi()); printf("%lld\n", cnt);
    return 0;
}

然后发现每一个数,要么加要么不加,优化(似乎并不快多少

using ll = long long;
using vi = vector<int>;
const ll MOD = 998244353;
int n; set<vi> res;
signed main() {
    n = rr; res.emplace(vi());
    rep(i, n) {
        int x = rr; auto bak = res;
        for (auto t : bak) t.push_back(x), res.emplace(t);
    } printf("%lld\n", ll(res.size()) % MOD);
    return 0;
}

然后不会优化了,老老实实找规律吧。

不久发现了规律。

设 \(f(i)\) 表示以 \(i\) 结尾的本质不同的子序列的个数。

先不考虑「本质不同」的要求,从左到右考虑:\(f(i)=\sum\limits_{j=1}^if(j)+\text{第 }i\text{ 个是否是该数字第一次出现}\).

然后考虑这个要求呢?发现如果这个数字不是第一次出现,那么它就不能从「前面与它相同的数字」的前面转移,因为那些东西已经被前面的那个数字计算过了。

特殊的,\(f(1)=1\)。然后再前缀和优化一下。

答案即是 \(\sum\limits_{i=1}^nf(i)\)。于是,解决。

using ll = long long;
using vi = vector<int>;
const int N = 1e6 + 10;
const ll MOD = 998244353;
map<int, int> appear;
int isfirst[N], tolast[N];
ll f[N], s[N];
signed main() {
    int n = rr; for (int i = 1; i <= n; ++i) {
        int a = rr; appear.count(a) ? tolast[i] = appear[a] : tolast[i] = isfirst[i] = 1;
        appear[a] = i;
    } f[1] = s[1] = 1; for (int i = 2; i <= n; ++i) {
        f[i] = (s[i - 1] - s[tolast[i] - 1] + isfirst[i] + MOD) % MOD;
        s[i] = (s[i - 1] + f[i]) % MOD;
    } printf("%lld\n", (s[n] + 1) % MOD);
    return 0;
}

T3

给定一个序列,多组询问,每组询问查询 \([l,r]\) 内极差为 \(k\) 的子区间数量。

思考过程:没有,不会,ST 表(打暴力)拿个部分分就完了。

const int N = 1e6 + 10;
const int K = 22;
int lg[N];
int f1[N][K], f2[N][K];
int q1(int l, int r) {
    int len = r - l + 1, k = lg[len];
    return max(f1[l][k], f1[r - (1 << k) + 1][k]);
} int q2(int l, int r) {
    int len = r - l + 1, k = lg[len];
    return min(f2[l][k], f2[r - (1 << k) + 1][k]);
} int main() {
    lg[1] = 0; for (int i = 2; i < N; ++i) lg[i] = lg[i >> 1] + 1;
    int n = rr, m = rr, k = rr; for (int i = 1; i <= n; ++i) f1[i][0] = f2[i][0] = rr;
    for (int j = 1; j < K; ++j) for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
        f1[i][j] = max(f1[i][j - 1], f1[i + (1 << j - 1)][j - 1]);
        f2[i][j] = min(f2[i][j - 1], f2[i + (1 << j - 1)][j - 1]);
    } while (m--) {
        int l = rr, r = rr; ll res = 0;
        for (int i = l; i <= r; ++i) for (int j = i; j <= r; ++j) if (q1(i, j) - q2(i, j) == k) ++res;
        printf("%lld\n", res);
    } return 0;
}

T4

有 \(2n\) 个二元组 \((a_i,b_i)\),现要两两分组,每一组对答案的贡献为,\(a+b\) 较大(如果相等则是 \(b\) 较大)的那个二元组的 \(a\).

思路:DFS 暴力偏分呗。

但是我懒,写了个全排列 next_permutation 就走人了,\(10\to5\text{pts}\)。

using ll = long long;
using pii = pair<int, int>;
using vi = vector<int>;
using vp = vector<pii>;
#define sum(x) (x.first + x.second)
int calc(pii a, pii b) {
    if (sum(a) != sum(b)) return sum(a) > sum(b) ? a.first : b.first;
    else return a.second > b.second ? a.first : b.first;
} signed main() {
    int n = rr, _1, _2; vp a; vi p;
    rep(_, 2 * n) _1 = rr, _2 = rr, a.push_back({_1, _2}), p.push_back(_);
    ll ans = 4e18; do {
        ll res = 0;
        for (int l = 0; l + 1 < p.size(); l += 2) res += calc(a[p[l]], a[p[l + 1]]);
        if (res < ans) ans = res;
    } while (next_permutation(p.begin(), p.end()));
    printf("%lld\n", ans);
    return 0;
}

T5

有一个排列,还有很多很多的操作,操作种类分为「« 循环右移一位 »、« 翻转 »、« 变为逆排列 »」。

一个排列 \(p\) 的逆排列定义为一个排列 \(p^{-1}\),满足 \(\forall i\in\mathbb{N}\cap[1,n],\ p_{p_i^{-1}}=i\)。

逆排列?没看懂。先模拟一下:\(\{4,3,1,2\}\to\{3,4,2,1\}\).

懂啦?没懂。再写个大的。然后才勉强理解(逃

然后,暴力(辣鸡的我。

using vi = vector<int>;
void turn(vi &a) {
    reverse(a.begin(), a.end());
} void move(vi &a) {
    int t = a.back();
    for (int i = a.size() - 1; i; --i) a[i] = a[i - 1];
    a[0] = t;
} void iv(vi &a) {
    int n = a.size(); vi t(n);
    for (int i = 0; i < n; ++i) t[a[i] - 1] = i + 1;
    a = t;
} signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, q; cin >> n >> q;
    vi a(n); rep(_, n) cin >> a[_];
    while (q--) {
        string s; int c; cin >> s >> c;
        while (c--) for (char op : s)
            if (op == 'S') move(a);
            else if (op == 'F') turn(a);
            else iv(a);
    } for (int _ : a) printf("%d ", _);
    return 0;
}

T6

一个有根树,以 \(1\) 为根,树上有点集 \(S\),每次点集中的每个元素向上移动,直到根 \(1\) 属于这个点集。求每次移动以后的点集大小 \(|S|\)。

不会,模拟完就走人。

const int N = 2e6 + 10;
vector<int> g[N]; void add(int u, int v) {
    g[u].push_back(v), g[v].push_back(u);
} int f[N]; void dfs(int u, int fa) {
    f[u] = fa; for (int v : g[u]) if (v != fa) dfs(v, u);
} signed main() {
    int n = rr; for (int i = 1; i < n; ++i) add(rr, rr);
    dfs(1, -1); int s = rr;
    set<int> d[2]; for (int i = 1; i <= s; ++i) d[0].emplace(rr);
    for (int k = 1; !d[k ^ 1].count(1); k ^= 1) {
        d[k].clear(); for (int i : d[k ^ 1]) d[k].emplace(f[i]);
        printf("%d ", (int)d[k].size());
    } return 0;
}

然后发现可以每次就把一个节点加到它的父亲上,但似乎一点用也没有。

const int N = 2e6 + 10;
vector<int> g[N]; void add(int u, int v) {
    g[u].push_back(v), g[v].push_back(u);
} int f[N]; void dfs(int u, int fa) {
    f[u] = fa; for (int v : g[u]) if (v != fa) dfs(v, u);
} signed main() {
    int n = rr; for (int i = 1; i < n; ++i) add(rr, rr);
    dfs(1, -1); int s = rr; set<int> d[2];
    for (int i = 1; i <= s; ++i) d[0].emplace(f[rr]);
    for (int k = 1; !d[k ^ 1].count(-1); k ^= 1) {
        printf("%d ", (int)d[k ^ 1].size()); d[k].clear();
        for (auto i : d[k ^ 1]) d[k].emplace(f[i]);
    } return 0;
}

T7

数论?不知道。看不懂而已(逃

T8

很懵,也没时间了,不写了。

「咱俩到 « 天台 » 逛逛吧」(大雾

T9

我为什么要看一个只有 \(1\text{pts}\) 的附加题?

总结

« 骗分过样例 »« 暴力出奇迹 »
« 暴搜挂着机 »« 打表出省一 »

标签:2023QDEZ,return,赛时,rr,int,res,ll,vi,八题
From: https://www.cnblogs.com/RainPPR/p/2023qdez-nr8t-code.html

相关文章

  • 前端歌谣的刷题之路-第五十八题-删除数组的最后一个元素
     前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从头再来歌谣的意志是永恒的放弃很容易但是坚持一定很酷本题目源自于牛客网微信公众号前端小歌谣题目......
  • 前端歌谣的刷题之路-第三十八题-大写字符串
     目录前言题目 核心代码总结前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从头再来歌谣的意志是永恒的放弃很容易但是坚持一定很酷本题目源自于牛客网......
  • 2014 蓝桥杯 预赛 c/c++ 本科B组 第八题:蚂蚁感冒(10')(4.9更新)
    第八题:蚂蚁感冒(10')  长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。   每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。  当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。  这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把......
  • JS逆向实战18——猿人学第八题 验证码 - 图文点选
    声明本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!网站https://match.yuanrenxue.cn/match/8网站分析首先进去就看到是如此复杂的文字验证码。我们首......
  • 跨年比赛记录(CF1777 赛时+补题)
    赛时开赛前,跟某位朋友说窝可能不会A,结果就真犯了离谱错误,一会儿没写输入一会儿写错输出,竟然9min才过A......
  • 每日八题--Git/禅道
    *******0105git&禅道面试题*********17.本地仓库初始化1)命令:gitinit2)什么叫初始化如果没有仓库就创建仓库,如果有仓库就清空18.远程仓库关联1)题意:本地工作区如何与远程......
  • 每日八题--Linux
    *********0104linux*********9.linux中常用目录解析/etc:存放配置文件mysql的配置文件默认在哪里?/usr/local/mysql/bin/mysqld/home:普通用户的家目录,在Linux中,每个用......
  • 每日八题
     *********0103数据库**********1.命令行数据库备份和还原首先配置数据库的环境变量:在mysql数据库中的bin目录下方式一:使用命令行备份和还原备份:cmd输入命令mysqldum......
  • 当项目经理看世界杯决赛时…
    12月18日,2022卡塔尔世界杯决赛,阿根廷在点球大战中击败卫冕冠军的法国队,捧走大力神杯。这场跌宕起伏的“巅峰对决”,给大家呈现了一场精彩绝伦的比赛。 当阿根廷2-0领先七......
  • #yyds干货盘点# 前端歌谣的刷题之路-第一百六十八题-object.create
     前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了......