2022赛前模测 提高组验题- 18

问题 A: 【2022NOIP联测2 10月2日】二分图排列

WA 15:为了让字典序最小,从前往后能改就改,我发现一个要向后连边的数一定不能被前面的数连过,所以它一定是前缀最大值,变相反数一定小于后面所以只需要和左侧的比较,就有几个判断,如果小于前缀Max就被连边,如果修改后小于被连边的最大值那就不修改,如果不修改依然小于下限,那就无解。

根据上面的错误结论,发现第二个数一定可以为负,但是这样就使被连边集合的mx变大了,可能导致误判为不合法。

如果排列中存在长度为3的下降序列,则图中一定存在奇环,所以修改后的排列a一定可以划分为不超过2个上升序列,即序列只能下降0次或1次。先倒序判断一下合法性,就可以在合法的基础上贪心地选了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 2;
const int inf = 0x3f3f3f3f;

int T, n, a[maxn], f[maxn][2];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void solve()
{
    n = read();
    for(int i=1; i<=n; i++) 
    {
        a[i] = read(); f[i][0] = f[i][1] = -inf;
    }
    f[n+1][0] = f[n+1][1] = inf;
    a[n+1] = inf;
    for(int i=n; i>=1; i--)
    {
        for(int j=0; j<2; j++)
        {
            int x = j ? -a[i] : a[i];
            if(x < a[i+1]) f[i][j] = max(f[i][j], f[i+1][0]);
            if(x < -a[i+1]) f[i][j] = max(f[i][j], f[i+1][1]);
            if(x < f[i+1][0]) f[i][j] = max(f[i][j], a[i+1]);
            if(x < f[i+1][1]) f[i][j] = max(f[i][j], -a[i+1]);
        }
        if(f[i][0] == -inf && f[i][1] == -inf)
        {
            printf("NO\n"); return;
        }
    }
    printf("YES\n");
    int l1 = -inf, l2 = -inf;
    for(int i=1; i<=n; i++)
    {
        if(-a[i] > l1)
        {
            l1 = -a[i]; printf("%d ", -a[i]);
        }
        else if(-a[i] > l2 && -a[i] < f[i][1])
        {
            l2 = -a[i]; printf("%d ", -a[i]);
        }
        else 
        {
            l1 = a[i]; printf("%d ", a[i]);
        }
        if(l1 < l2) swap(l1, l2);
    }
    printf("\n");
}

int main()
{  
    T = read();
    while(T--) solve();
    
    return 0;
}
%%%sadom才注意到没有a

 

问题 B: 【2022NOIP联测2 10月2日】最短路问题 V3

我把我写的这个改了改格式去最短路的专题里都能A某些东西,比如:信使,对,这题的数据很水,但是我把它交到accoders上不是T了而是错了!!WA 20……这有点离谱?然后注释掉的就是这个B的错误写法:有大佬知道它为什么不对吗***

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 500;
const ll inf = 1e17;

int n, m, q, ff[maxn], stk[maxn], cnt, id[maxn];
ll ans, dis[maxn];
bool vis[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
struct node 
{
    int next, to, w;
}a[maxn<<1], e[maxn<<1];
int len, tot, head[maxn], h[maxn];
void add(int x, int y, int w)
{
    a[++len].to = y; a[len].next = head[x]; a[len].w = w;
    head[x] = len;
}
void add_tree(int x, int y, int w)
{
    e[++tot].to = y; e[tot].next = h[x]; e[tot].w = w;
    h[x] = tot;
}
inline void New(int x) {if(id[x]) return; stk[++cnt] = x; id[x] = cnt;}
int fa[maxn], dep[maxn], siz[maxn], son[maxn], top[maxn];
void find_heavy_edge(int u, int fat, int depth)
{
    //printf("u = %d\n", u);
    fa[u] = fat;
    dep[u] = depth;
    siz[u] = 1;
    son[u] = 0;
    int maxsize = 0;

    for(int i=h[u]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(dep[v]) continue;
        dis[v] = dis[u] + e[i].w;
        find_heavy_edge(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}
void connect_heavy_edge(int u, int ancestor)
{
    top[u] = ancestor;
    if(son[u])
    {
        connect_heavy_edge(son[u], ancestor);
    }
    for(int i=h[u]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(v == son[u] || v == fa[u]) continue;
        connect_heavy_edge(v, v);
    }
}
int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[x] < dep[y]) swap(x, y);
        x = fa[top[x]];
        //printf("x = %d y = %d\n", x, y);
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}
int find(int x)
{
    if(x == ff[x]) return x;
    return ff[x] = find(ff[x]);
}
queue<int> qu;
ll d[44][maxn];
void spfa(int st)
{
    for(int i=1; i<=n; i++) d[id[st]][i] = inf;
    d[id[st]][st] = 0;
    vis[st] = 1;
    qu.push(st);
    while(!qu.empty())
    {
        int x = qu.front(); qu.pop();
        vis[x] = 0;
        for(int i=head[x]; i; i=a[i].next)
        {
            int y = a[i].to;
            if(d[id[st]][y] > d[id[st]][x] + a[i].w)
            {
                d[id[st]][y] = d[id[st]][x] + a[i].w;
                if(!vis[y])
                {
                    vis[y] = 1; qu.push(y);
                }
            }
        }
    }
}

int main()
{
    //freopen("1.in", "r", stdin);
    n = read(); m = read();
    for(int i=1; i<=n; i++) ff[i] = i;
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w); add(v, u, w);
        int fx = find(u), fy = find(v);
        if(fx == fy) 
        {
            New(u); New(v);
            continue;
        }
        ff[fx] = fy;
        add_tree(u, v, w); add_tree(v, u, w);
    }
    find_heavy_edge(1, 0, 1);
    connect_heavy_edge(1, 1);
    for(int i=1; i<=cnt; i++)
    {
        spfa(stk[i]);
    }
    /*q = read();
    while(q--)
    {
        int u = read(), v = read();
        int lca = LCA(u, v);
        ans = dis[u] + dis[v] - dis[lca] - dis[lca];
        for(int i=1; i<=cnt; i++)
        {
            ans = min(ans, d[i][u]+d[i][v]);
        }
        printf("%lld\n", ans);
    }*/
    ll res = 0;
    for(int i=2; i<=n; i++)
    {
        int lca = LCA(1, i);
        res = dis[i] - dis[lca] - dis[lca];
        for(int j=1; j<=cnt; j++)
        {
            res = min(res, d[j][1]+d[j][i]);
        }
        //printf("res[%d] = %lld\n", i, res);
        ans = max(ans, res);
    }
    printf("%lld\n", ans);
    
    return 0;
}
View Code

 一定要建一棵最小生成树吗??

我又去鹤了一个,它A了,但我还是想知道为什么以上不对……

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 50;
const ll inf = 1e17;
typedef pair<ll, int> paint;

int n, m, q, ff[maxn], spc[maxn];
ll ans, dis[50][maxn], gap[maxn];
bool vs[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge
{
    int to, w, next, op;
}a[maxn<<1];
int head[maxn], len;
struct node2
{
    int u, v, w;
    bool operator < (const node2 &T) const 
    {
        return w < T.w;
    }
}s[maxn];
priority_queue <paint, vector<paint>, greater<paint> > sml;
void dij(int st, ll dis[])
{
    memset(vs, 0, sizeof(vs));
    dis[st] = 0;
    sml.push(make_pair(dis[st], st));
    while(!sml.empty())
    {
        int u = sml.top().second; sml.pop();
        if(vs[u]) continue;
        vs[u] = 1;
        for(int i=head[u]; i; i=a[i].next)
        {
            int v = a[i].to;
            if(dis[v] > dis[u] + a[i].w)
            {
                dis[v] = dis[u] + a[i].w;
                sml.push(make_pair(dis[v], v));
            }
        } 
    }
}
void add(int x, int y, int w, int op)
{
    a[++len] = edge{y, w, head[x], op}; head[x] = len;
    if(op)
    {
        if(!vs[x]) spc[++spc[0]] = x;
        if(!vs[y]) spc[++spc[0]] = y;
        vs[x] = vs[y] = 1;
    }
}
int find(int x)
{
    if(x == ff[x]) return x;
    return ff[x] = find(ff[x]);
}
void un(int x, int y)
{
    ff[find(x)] = find(y);
}
void Kru()
{
    sort(s+1, s+1+m);
    for(int i=1; i<=n; i++) ff[i] = i;
    for(int i=1; i<=m; i++)
    {
        if(find(s[i].u) != find(s[i].v))
        {
            add(s[i].u, s[i].v, s[i].w, 0); add(s[i].v, s[i].u, s[i].w, 0);
            un(s[i].u, s[i].v);
        }
        else add(s[i].u, s[i].v, s[i].w, 1), add(s[i].v, s[i].u, s[i].w, 1);
    }
}
int dep[maxn], dad[maxn][30];
void dfs(int u, int fa)
{
    dep[u] = dep[fa] + 1;
    dad[u][0] = fa;
    int t = log2(dep[u]) + 1;
    for(int i=1; i<=t; i++) dad[u][i] = dad[dad[u][i-1]][i-1];
    for(int i=head[u]; i; i=a[i].next)
    {
        int to = a[i].to;
        if(to == fa || a[i].op) continue;
        gap[to] = gap[u] + a[i].w;
        dfs(to, u);
    }
}
int LCA(int x, int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    for(int i=18; i>=0; i--)
    {
        if(dep[dad[x][i]] >= dep[y]) x = dad[x][i];
    }
    for(int i=18; i>=0; i--)
    {
        if(dad[x][i] != dad[y][i]) x = dad[x][i], y = dad[y][i];
    }
    return x == y ? x : dad[x][0];
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read(), w = read();
        s[i] = {u, v, w};
    }
    Kru();
    memset(dis, 0x3f, sizeof(dis));
    for(int i=1; i<=spc[0]; i++) dij(spc[i], dis[i]);
    dfs(1, 0);
    q = read();
    while(q--)
    {
        int u = read(), v = read(), lca = LCA(u, v);
        ans = gap[u] + gap[v] - 2 * gap[lca];
        for(int i=1; i<=spc[0]; i++) ans = min(ans, dis[i][u]+dis[i][v]);
        printf("%lld\n", ans);
    }
    
    return 0;
}
View Code

upd 10.2 17:32

并不需要建一棵最小生成树,是的就是树剖写挂了%%%TSTYFST%%%

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 500;
const ll inf = 1e17;

int n, m, q, ff[maxn], stk[maxn], cnt, id[maxn];
ll ans, dis[maxn];
bool vis[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
struct node 
{
    int next, to, w;
}a[maxn<<1], e[maxn<<1];
int len, tot, head[maxn], h[maxn];
void add(int x, int y, int w)
{
    a[++len].to = y; a[len].next = head[x]; a[len].w = w;
    head[x] = len;
}
void add_tree(int x, int y, int w)
{
    e[++tot].to = y; e[tot].next = h[x]; e[tot].w = w;
    h[x] = tot;
}
inline void New(int x) {if(id[x]) return; stk[++cnt] = x; id[x] = cnt;}
int fa[maxn], dep[maxn], siz[maxn], son[maxn], top[maxn];
void find_heavy_edge(int u, int fat, int depth)
{
    //printf("u = %d\n", u);
    fa[u] = fat;
    dep[u] = depth;
    siz[u] = 1;
    son[u] = 0;
    int maxsize = 0;

    for(int i=h[u]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(dep[v]) continue;
        dis[v] = dis[u] + e[i].w;
        find_heavy_edge(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}
void connect_heavy_edge(int u, int ancestor)
{
    top[u] = ancestor;
    if(son[u])
    {
        connect_heavy_edge(son[u], ancestor);
    }
    for(int i=h[u]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(v == son[u] || v == fa[u]) continue;
        connect_heavy_edge(v, v);
    }
}
int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
        //printf("x = %d y = %d\n", x, y);
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}
int find(int x)
{
    if(x == ff[x]) return x;
    return ff[x] = find(ff[x]);
}
queue<int> qu;
ll d[44][maxn];
void spfa(int st)
{
    for(int i=1; i<=n; i++) d[id[st]][i] = inf;
    d[id[st]][st] = 0;
    vis[st] = 1;
    qu.push(st);
    while(!qu.empty())
    {
        int x = qu.front(); qu.pop();
        vis[x] = 0;
        for(int i=head[x]; i; i=a[i].next)
        {
            int y = a[i].to;
            if(d[id[st]][y] > d[id[st]][x] + a[i].w)
            {
                d[id[st]][y] = d[id[st]][x] + a[i].w;
                if(!vis[y])
                {
                    vis[y] = 1; qu.push(y);
                }
            }
        }
    }
}

int main()
{
    //freopen("1.in", "r", stdin);
    n = read(); m = read();
    for(int i=1; i<=n; i++) ff[i] = i;
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w); add(v, u, w);
        int fx = find(u), fy = find(v);
        if(fx == fy) 
        {
            New(u); New(v);
            continue;
        }
        ff[fx] = fy;
        add_tree(u, v, w); add_tree(v, u, w);
    }
    find_heavy_edge(1, 0, 1);
    connect_heavy_edge(1, 1);
    for(int i=1; i<=cnt; i++)
    {
        spfa(stk[i]);
    }
    q = read();
    while(q--)
    {
        int u = read(), v = read();
        int lca = LCA(u, v);
        ans = dis[u] + dis[v] - dis[lca] - dis[lca];
        for(int i=1; i<=cnt; i++)
        {
            ans = min(ans, d[i][u]+d[i][v]);
        }
        printf("%lld\n", ans);
    }
    
    return 0;
}
View Code

但是求个最小生成树也不是不可以,Cat又把鹤的题解的版本改成了ShuLianPouFen

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 50;
const ll inf = 1e17;
typedef pair<ll, int> paint;

int n, m, q, ff[maxn], spc[maxn];
ll ans, gap[maxn], dis[50][maxn];
bool vs[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge 
{
    int u, v, w;
    bool operator < (const edge &T) const 
    {
        return w < T.w;
    }
}s[maxn];
struct node 
{
    int next, to, w, op;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y, int w, int op)
{
    //printf("op = %d\n", op);
    a[++len] = {head[x], y, w, op}; head[x] = len;
    if(op)
    {
        if(!vs[x]) spc[++spc[0]] = x;
        if(!vs[y]) spc[++spc[0]] = y;
        vs[x] = vs[y] = 1;
    }
}
int find(int x)
{
    if(x == ff[x]) return x;
    return ff[x] = find(ff[x]);
}
void un(int x, int y) {ff[find(x)] = find(y);}
void Kru()
{
    sort(s+1, s+1+m);
    for(int i=1; i<=m; i++)
    {
        if(find(s[i].u) != find(s[i].v))
        {
            add(s[i].u, s[i].v, s[i].w, 0); add(s[i].v, s[i].u, s[i].w, 0);
            un(s[i].u, s[i].v);
        }
        else add(s[i].u, s[i].v, s[i].w, 1), add(s[i].v, s[i].u, s[i].w, 1);
    }
}
int fa[maxn], dep[maxn], son[maxn], siz[maxn], top[maxn];
void find_heavy_edge(int u, int fat, int depth)
{
    //printf("u = %d", u);
    fa[u] = fat;
    dep[u] = depth;
    son[u] = 0;
    siz[u] = 1;
    int maxsize = 0;
    //printf("head[%d] = %d\n", u, head[u]);

    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        //printf("dep[%d] = %d\n", v, dep[v]);
        //printf("op = %d\n", a[i].op);
        if(dep[v] || a[i].op) continue;
        gap[v] = gap[u] + a[i].w;
        //printf("gap[%d] = %lld\n", v, gap[v]);
        find_heavy_edge(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}
void connect_heavy_edge(int u, int ancestor)
{
    //printf("------u = %d\n", u);
    top[u] = ancestor;
    if(son[u])
    {
        connect_heavy_edge(son[u], ancestor);
    }
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        //printf("v = %d\n", v);
        //if(v == 3) exit(0);
        if(v == son[u] || v == fa[u] || a[i].op) continue;
        connect_heavy_edge(v, v);
    }
}
int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}
priority_queue<paint, vector<paint>, greater<paint> > sml;
void dij(int st, ll dis[])
{
    memset(vs, 0, sizeof(vs));
    dis[st] = 0;
    sml.push(make_pair(dis[st], st));
    while(!sml.empty())
    {
        int u = sml.top().second; sml.pop();
        if(vs[u]) continue;
        vs[u] = 1;
        for(int i=head[u]; i; i=a[i].next)
        {
            int v = a[i].to;
            if(dis[v] > dis[u] + a[i].w)
            {
                dis[v] = dis[u] + a[i].w;
                sml.push(make_pair(dis[v], v));
            }
        }
    }
}

int main()
{
    n = read(); m = read(); 
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read(), w = read();
        s[i] = (edge){u, v, w};
    }
    for(int i=1; i<=n; i++) ff[i] = i;
    Kru();
    find_heavy_edge(1, 0, 1);
    //printf("111\n\n\n");
    connect_heavy_edge(1, 1);
    memset(dis, 0x3f, sizeof(dis));
    for(int i=1; i<=spc[0]; i++) dij(spc[i], dis[i]);
    q = read();
    while(q--)
    {
        int u = read(), v = read(), lca = LCA(u, v);
        ans = gap[u] + gap[v] - 2 * gap[lca];
        //printf("ans = %lld\n", ans);
        for(int i=1; i<=spc[0]; i++) ans = min(ans, dis[i][u]+dis[i][v]);
        printf("%lld\n", ans);
    }
    
    return 0;
}
View Code

 

问题 C: 【2022NOIP联测2 10月2日】捡石子游戏

官方题解不错我要了:

不能用权值最小的节点为根求深度然后判奇偶性,不一定所有的点都能到达点权最小的那个,但是所有的点都有一个边界,还是对每个点dfs吧。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 3003;
const int inf = 0x3f3f3f3f;

int n, c[maxn];
bool f;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int next, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

int dfs(int u, int fa)
{
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v != fa && c[u] > c[v] && !dfs(v, u)) return 1;
    }
    return 0;
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++) c[i] = read();
    for(int i=1; i<n; i++)
    {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }
    for(int i=1; i<=n; i++)
    {
        if(dfs(i, 0))
        {
            printf("%d ", i);
            f = 1;
        }
    }
    if(!f) printf("-1");
    
    return 0;
}
View Code

 

问题 D: 【2022NOIP联测2 10月2日】凹函数

咕了……

posted @ 2022-10-02 15:42  Catherine_leah  阅读(41)  评论(9编辑  收藏  举报
/* */