首页 > 其他分享 >2023.02.17 模拟赛小结

2023.02.17 模拟赛小结

时间:2023-03-05 12:58:09浏览次数:70  
标签:return 17 int 2023.02 ret read 小结 void define

2023.02.17 模拟赛小结

目录

更好的阅读体验戳此进入

赛时思路

T1

有一道类似的 “原题”:LG-P3411 序列变换

给定排列 $ A_n $,每次操作可以将任一元素丢到排列头或尾,最小化操作次数,输出最小值并输出任意方案。

签到题,考虑维护数值上连续但位置可以单调不连续的最长上升子序列,简单 DP 即可,方案处理平凡。

对于 “原题” 区别就是序列改为排列,离散化一下处理一下相同的即可。假了,这东西不能 DP,错误性显然,考虑单调队列,正解放在后文。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;



template < typename T = int >
inline T read(void);

int N;
int A[110000];
int pos[110000];
// bitset < 110000 > vis;
int dp[110000];
int mx(0), mxv(-1);

int main(){
    freopen("sort.in", "r", stdin);
    freopen("sort.out", "w", stdout);
    N = read();
    for(int i = 1; i <= N; ++i)pos[A[i] = read()] = i;
    for(int i = 1; i <= N; ++i){
        dp[A[i]] = dp[A[i] - 1] + 1;
        if(dp[A[i]] > mx)mx = dp[A[i]], mxv = A[i];
    }
    int lim1 = mxv - mx + 1, lim2 = mxv;
    printf("%d\n", N - mx);
    for(int i = lim1 - 1; i; --i)printf("%d 0\n", i);
    for(int i = lim2 + 1; i <= N; ++i)printf("%d 1\n", i);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

T2

原题 LG-P3603 雪辉

给定 $ n $ 个点的树,存在点权,多次询问每次给定多对点分别表示一条树链,求所有树链中有多少不同点权,及其点权的 $ \operatorname{mex} $。强制在线。

首先看到计算不同点权和求 $ \operatorname{mex} $ 且值域不大,自然想到 bitset,当我们求得答案的 bitset,我们只需要调用 count() 即可获得点权种类数,将其取反后,调用 _Find_first() 即可获得 $ \operatorname{mex} \(。且上述所有操作均会除去一个 `bitset` 特有的,\) w $ 的复杂度。

这里的 $ w $ 根据编译器版本一般为 $ 32 $ 或 $ 64 $,且这里记作 $ w $ 而不是 $ \omega $ 是因为个人认为理解为 word 较为合理。

考虑如何维护,首先提供一个十分显然的思路,对原树进行树剖,然后在线段树上每个节点均开一个 bitset 建树,令 $ v $ 表示点权,这样的复杂度显然是 $ O(\dfrac{nv}{w}) $ 的,而对于每次询问,直接查询并强行合并,分析这样的复杂度:树剖有一只 $ O(\log n) $,线段树上查询的节点数是 $ O(\log n) $,每次合并需要 $ O(\dfrac{v}{w}) $,若共 $ q $ 次询问则最终复杂度 $ O(\dfrac{qv\log^2 n}{w}) $,显然无法通过,但是本题似乎限制较小,这样也可以通过。

考虑分析上述做法的空间复杂度,显然为 $ O(\dfrac{nv}{w}) $,但是线段树一般有一个 $ 4 $ 的空间常数,简单计算发现精细实现后大致需要 $ 262413 $,这样大致需要 1GiB,考虑优化,显然对于线段树的底层每个点仅维护了一个数,而倒数第二层每个点仅维护了两个数,于是不难想到我们将倒数这两层改为用 pair 维护即可,这样可以去掉 $ 131072 + 65536 $ 左右个 bitset 的空间复杂度,优化极大,空间冗余较多,实现平凡。

下面提供一个来自 @Zpair 的高妙思路,可以将复杂度去掉一只 $ O(\log n) $,显然这样的复杂度就是理论正确的了。即考虑在树剖后每个重链上维护这整个重链的 bitset,同时类似上文维护线段树,对于每次询问中,所有整个重链的查询直接调用,容易证明残缺的重链查询最多有 $ 3 $ 次,可以认为是常数,故优化掉一只 $ O(\log n) $,容易证明这样的复杂度在当前时空限制是可以通过的。同时若空间无法通过还可考虑对于所有点数小于 $ \dfrac{v}{w} $ 的直接用 basic_string 维护,这样可以更进一步地大幅优化空间。

当然这里因为前者虽然复杂度错误但常数不大可以通过,于是这里直接挂前者的代码了。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#include <bitset>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define LIM (110000)

template < typename T = int >
inline T read(void);

int N, Q, F;
struct Edge{
    Edge* nxt;
    int to;
    OPNEW;
}ed[LIM << 1];
ROPNEW;
Edge* head[LIM];
int val[LIM];
int lst(0);

int dep[LIM], hson[LIM], top[LIM], fa[LIM], siz[LIM], dfn[LIM], idx[LIM];

void dfs_pre(int p = 1, int fa = 0){
    ::fa[p] = fa, dep[p] = dep[fa] + 1, siz[p] = 1;
    for(auto i = head[p]; i; i = i->nxt){
        if(SON == fa)continue;
        dfs_pre(SON, p);
        siz[p] += siz[SON];
        if(siz[SON] > siz[hson[p]])hson[p] = SON;
    }
}
void dfs_make(int p = 1, int top = 1){
    static int cdfn(0);
    dfn[p] = ++cdfn, idx[cdfn] = p;
    ::top[p] = top;
    if(hson[p])dfs_make(hson[p], top);
    for(auto i = head[p]; i; i = i->nxt){
        if(SON == fa[p] || SON == hson[p])continue;
        dfs_make(SON, SON);
    }
}

class SegTree{
private:
    //sum is 262143
    bitset < 30010 > tr[120000];
    pair < int, int > base[LIM << 2];
    #define LS (p << 1)
    #define RS (LS | 1)
    #define MID ((gl + gr) >> 1)
public:
    void Pushup(int p, int gl, int gr){
        if(gr - gl + 1 <= 2)return;
        if(MID - gl + 1 == 1)tr[p][base[LS].first] = true;
        else if(MID - gl + 1 == 2)tr[p][base[LS].first] = tr[p][base[LS].second] = true;
        else tr[p] |= tr[LS];
        if(gr - (MID + 1) + 1 == 1)tr[p][base[RS].first] = true;
        else if(gr - (MID + 1) + 1 == 2)tr[p][base[RS].first] = tr[p][base[RS].second] = true;
        else tr[p] |= tr[RS];
    }
    void Build(int p = 1, int gl = 1, int gr = N){
        if(gl == gr)return base[p] = {val[idx[gl = gr]], -1}, void();
        if(gr - gl + 1 == 2)base[p] = {val[idx[gl]], val[idx[gr]]};
        Build(LS, gl, MID), Build(RS, MID + 1, gr);
        Pushup(p, gl, gr);
    }
    auto Query(int l, int r, int p = 1, int gl = 1, int gr = N){
        bitset < 30010 > ret; ret.reset();
        if(l <= gl && gr <= r){
            if(gl == gr){ret[base[p].first] = true; return ret;}
            if(gr - gl + 1 == 2){ret[base[p].first] = ret[base[p].second] = true; return ret;}
            return tr[p];
        }
        if(l <= MID)ret |= Query(l, r, LS, gl, MID);
        if(r >= MID + 1)ret |= Query(l, r, RS, MID + 1, gr);
        return ret;
    }
}st;

auto Query(int s, int t){
    bitset < 30010 > ret; ret.reset();
    while(top[s] != top[t]){
        if(dep[top[s]] < dep[top[t]])swap(s, t);
        ret |= st.Query(dfn[top[s]], dfn[s]);
        s = fa[top[s]];
    }if(dep[s] < dep[t])swap(s, t);
    ret |= st.Query(dfn[t], dfn[s]);
    return ret;
}

int main(){
    N = read(), Q = read(), F = read();
    for(int i = 1; i <= N; ++i)val[i] = read();
    for(int i = 1; i <= N - 1; ++i){
        int s = read(), t = read();
        head[s] = new Edge{head[s], t};
        head[t] = new Edge{head[t], s};
    }dfs_pre(), dfs_make();
    st.Build();
    while(Q--){
        int M = read();
        bitset < 30010 > ans; ans.reset();
        for(int i = 1; i <= M; ++i){
            int s = read() ^ (lst * F), t = read() ^ (lst * F);
            ans |= Query(s, t);
        }
        int ans1 = ans.count(), ans2 = (~ans)._Find_first();
        lst = ans1 + ans2;
        printf("%d %d\n", ans1, ans2);
    }
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

T3

题意懒得写了,一道奇怪题,暴力思路容易想到,正解大概是要用到一点智慧,不太喜欢这道题。

但是该说不说,这题数据真的水,常数不是大的离谱的暴力直接过了 $ 80\texttt{pts} $。

Code

/*
2
5 1 49
8
2
1
7
9
5 1 64
8
2
1
7
9
*/
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;



template < typename T = int >
inline T read(void);

int N, M; ll K;
ll A[510000];
int ans(0);
// deque < ll > q1, q2;
// basic_string < ll > tmp;

int main(){
    freopen("cont.in", "r", stdin);
    freopen("cont.out", "w", stdout);
    int T = read();
    while(T--){
        // q1.clear(), q2.clear(), tmp.clear();
        ans = 0;
        N = read(), M = read(), K = read < ll >();
        for(int i = 1; i <= N; ++i)A[i] = read();
        int cur(1);
        basic_string < ll > vals;
        while(cur <= N){
            ++ans;
            vals.clear();
            vals += A[cur];
            // tmp += A[cur];
            for(int i = cur + 1; i <= N; ++i){
                vals.insert(lower_bound(vals.begin(), vals.end(), A[i]), A[i]);
                ll sum(0);
                for(int l = 1, r = vals.size(), c = 1; l <= r && c <= M; ++l, --r, ++c)
                    sum += (vals.at(r - 1) - vals.at(l - 1)) * (vals.at(r - 1) - vals.at(l - 1));
                if(sum > K)break;
                cur = i;
            }++cur;
        }printf("%d\n", ans);
    }
    
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

正解

T1

我们思考一下要找的序列的本质,整个序列需要保证不降,且对于值域为 $ [l, r] $,所有值域在 $ [l + 1, r - 1] $ 的元素都需要完全在队列内。

考虑维护,不难想到记录每个数的每个位置,当我们插一个数时,枚举插入数量,或者说最大的插入位置,当插入该位置的时候需要将单调队列末尾所有位置在此之后的都弹出,而当弹出一个值的时候,因为偶我们要将当前数插入,所以弹出的值一定会被删得不完全,所以全部不大于那个数得都要丢掉,以此处理一下即可。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N;
int A[1100000];
basic_string < int > vals[1100000];
int mx(0);

int main(){
    N = read();
    for(int i = 1; i <= N; ++i)vals[A[i] = read()] += i;
    deque < int > cur;
    for(int i = 1; i <= 1000000; ++i){
        for(int j = vals[i].size(); j >= 1; --j){
            int v = vals[i].at(j - 1);
            while(!cur.empty() && cur.back() > v){
                while(!cur.empty() && A[cur.front()] < A[cur.back()])cur.pop_front();
                cur.pop_back();
            }mx = max(mx, (int)cur.size() + (int)vals[i].size() - j + 1);
        }
        for(int j = 1; j <= (int)vals[i].size(); ++j)cur.emplace_back(vals[i].at(j - 1));
    }printf("%d\n", N - mx);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

T2

正解上文写过了(值得一提的是出题人造数据的时候没加强制在线锅掉了,导致大多数人都爆零。。

UPD

update-2023_02_17 初稿

标签:return,17,int,2023.02,ret,read,小结,void,define
From: https://www.cnblogs.com/tsawke/p/17180235.html

相关文章

  • 2023.02.21 模拟赛小结
    2023.02.21模拟赛小结目录2023.02.21模拟赛小结更好的阅读体验戳此进入赛时思路T1CodeT2CodeT3CodeT4Code正解T1CodeT2CodeT3T4UPD更好的阅读体验戳此进入赛时思路T1......
  • 杂题小记(2023.02.22)
    杂题小记(2023.02.22)目录杂题小记(2023.02.22)更好的阅读体验戳此进入HDU-3038HowManyAnswersAreWrong题面SolutionCodeLG-P1525[NOIP2010提高组]关押罪犯题面Soluti......
  • 杂题小记(2023.02.24)
    杂题小记(2023.02.24)目录杂题小记(2023.02.24)更好的阅读体验戳此进入LG-P5251[LnOI2019]第二代图灵机题面SolutionCodeLG-P3765总统选举题面SolutionCodeUPD更好的阅读体......
  • 杂题小记(2023.02.27)
    杂题小记(2023.02.27)目录杂题小记(2023.02.27)更好的阅读体验戳此进入LG-P3865【模板】ST表LG-P3293[SCOI2016]美味题面SolutionCodeLG-P5490【模板】扫描线题面Solution......
  • 杂题小记(2023.02.28)
    杂题小记(2023.02.28)目录杂题小记(2023.02.28)更好的阅读体验戳此进入SP2713GSS4-CanyouanswerthesequeriesIV题面SolutionCodeLG-P4391[BOI2009]RadioTransmissio......
  • CF1778F Maximizing Root - 树形 dp -
    题目链接:https://codeforces.com/problemset/problem/1778/F题解:设\(dp_{i,j}\)表示考虑到\(i\)结点,要让子树内的点都变成\(a_i\)第\(j\)小约数的倍数的话,至少要......
  • 【LeetCode二叉树#17】在二叉搜索树中插入或删除某个值(涉及重构二叉树、链表基础、以
    二叉搜索树中的插入操作力扣题目链接(opensnewwindow)给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。返回插入后二叉搜索树的根节点。输入数据保证......
  • 【喜报】高科技PCB行业排头兵企业S/4HANA 1709拆分项目成功上线
    2023年2月20日,SNP与金牌合作伙伴–上海翰耐信息科技有限公司一起合作的高科技行业某客户S/4HANA1709拆分项目成功上线。此项目为SNP中国的又一单S/4拆分项目。祝贺中国......
  • 进制转换 洛谷P1017
    题目传送门题目描述我们可以用这样的方式来表示一个十进制数:将每个阿拉伯数字乘以一个以该数字所处位置为指数,以 1010 为底数的幂之和的形式。例如 123123 可表......
  • CF1175G Yet Another Partiton Problem
    \(\text{Solution}\)有关斜率优化的强势套娃题,感觉套出了巅峰我整整写了5个小时、、、简单\(dp\)\[f_{i,j}=f_{i-1,k-1}+(j-k+1)\max_{l=k}^ja_l\]固定这个最......