【补】2022.7.26———HZOI【暑假多校联训6】 游寄

Write In Front

咱就是说多校的题水

多少分忘了,TLEcoders不想上

T1:Start T2:Dream T3:It T4:Possible

T1 Start

大模拟。

很好。很他妈棒。

大模拟都很简单。但是话是这么说。

所以这个题在我重构了N遍之后仍然没有A

T2 Dream

这其实是一道构造题。

原串是2n长的

然后Su_Zipei学长给复制了一下变成了4n长的

所以说,4n长的串,左边2n长有ngnz,右边也是

因为他问的是公共子序列,所以不需要连续

很显然地想到左边ng,右边nz,这样就凑了2n个了

最后在末尾加一个g,这样便能普适所有的串

正确性?

ggzz -> ggzzggzz

gzgz -> gzgzgzgz

zgzg -> zgzgzgzg

zzgg -> zzggzzgg

也就是说,不管你怎么卡,你是卡不掉这个构造的

当你限制g和z顺序的时候,右边的复制会把n个z复制出来,这样你又卡不掉了

具体的证明见下发文件的题解,我不会证明,反正确实可以这样构造

代码

#include <iostream>
#include <iomanip>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define MARK cout << "###"
#define _MARK "@@@"
#define LMARK "!!!~~~"
#define ZY " qwq "
#define _ " "
#define Endl cout << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false);cin.tie(NULL), cout.tie(NULL);}
int n;
void work(){
    cin >> n;
    for (re i = 1 ; i <= n ; ++ i) cout << 'g';
    for (re i = 1 ; i <= n ; ++ i) cout << 'z';
    cout << 'g' << '\n';
}
// #define IXINGMY
char_phi main(){
    #ifdef IXINGMY
        FBI_OPENTHEDOOR(a);
    #endif
    Fastio_setup();
    work();
    return GMY;
}

T3 It

考场上以为这是水题,结果爆大零了,伤心

正解有很多,感觉各位都是查分约束或者找规律等等,这里我就说说@dbxtopo排序

这种做法比较奇特(((

似乎没发现除了dbx之外的人用这个?((


首先缩块,O(n)扫一遍把连续着的ai相同的给变成一个块,然后不相同的自成别的块

然后对ai小的往ai大的建有向边,边权为1,因为要平均分最小

然后就统计所有入度为0(也就是ai比相邻两边都小的)点,然后扔到队列里,开始跑拓扑

由于拓扑了所以有先后的更新顺序可以保证答案的正确性

实在不懂就造个样例手模

具体实现,代码:

#include <iostream>
#include <iomanip>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define MARK cout << "###"
#define _MARK "@@@"
#define LMARK "!!!~~~"
#define ZY " qwq "
#define _ " "
#define Endl cout << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 1000005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false);cin.tie(NULL), cout.tie(NULL);}
int n, L, R(-1), star_cnt, kuai_num;
int a[N], head[N], k[N][100], ru[N], ans[N];
struct star{
    int v, w, nxt;
}e[N<<1];
struct node{
    int id, w;
}q[N];
inline void star_add(int u, int v, int w){e[++ star_cnt].v=v, e[star_cnt].w=w, e[star_cnt].nxt=head[u], head[u]=star_cnt, ++ ru[v];}// w:+1
void work(){
    // hxqasd拓扑
    // 确实看起来很简单
    // 搞!
    cin >> n;
    for (re i = 1 ; i <= n ; ++ i){
        cin >> a[i];
        if (a[i] == a[i-1]) k[kuai_num][++ k[kuai_num][0]] = i;
        else k[++ kuai_num][++ k[kuai_num][0]] = i;// 开新坑
    }
    for (re i = 2 ; i <= kuai_num ; ++ i){
        if (a[k[i][1]] > a[k[i-1][1]]) star_add(i-1, i, 1);// 一个由小的指向大的
        else star_add(i, i-1, 1);// , cout << i << _ << i-1 << '\n'
    }
    // for (re i = 1 ; i <= kuai_num ; ++ i)
    //     cout << ru[i] << _;
    // Endl;
    // for (re i = 1 ; i <= kuai_num ; ++ i){
    //     MARK, cout << _ << _;
    //     for (re j = 1 ; j <= k[i][0] ; ++ j){
    //         cout << k[i][j] << _;
    //     }
    //     Endl;
    // }
    for (re i = 1 ; i <= kuai_num ; ++ i)
        if (ru[i] == 0)
            q[++ R] = (node){i, 1};
    node leader;
    while (L <= R){
        // MARK;
        leader = q[L], ++ L, ans[leader.id] = leader.w;
        for (re i = head[leader.id] ; i ; i = e[i].nxt){
            ru[e[i].v] --;
            if (ru[e[i].v] == 0){
                q[++ R] = (node){e[i].v, leader.w+e[i].w};// 精髓在此
            }
        }
    }
    for (re i = 1 ; i <= kuai_num ; ++ i){
        for (re j = 1 ; j <= k[i][0] ; ++ j){
            cout << ans[i] << _;
        }
    }
    Endl;
}
// #define IXINGMY
char_phi main(){
    #ifdef IXINGMY
        FBI_OPENTHEDOOR(a);
    #endif
    Fastio_setup();
    work();
    return GMY;
}

T4 Possible

这个题思路巧,LCA+最短路

因为题目中说了,

保证输入的前 n-1 条边是树边,剩下的 m-n+1 条边是返祖边。

所以可以先求出来原树的所有信息来。


首先我们考虑这样一张图,要求的是6~9的最短路:

image
69LCA4

如果完全按照树边LCA走,会得到65489总和为9的路。

设两个点xy,他们的LCAlca

如果对4的子树(包括4)跑一个Dijkstra,可以获得dis[lca][x]+dis[lca][y]即dis[4][6] + dis[4][9] = 86549总和为8的路。

但是显然还有更短的。654329总和为7的路怎么处理?

答案是从lca进一步往上跳。令lca = fa[lca][0]直到跳到lca = 0,期间更新final_ans的值,也就是

while (lca != 0){
	final_ans = MIN(final_ans, dis[lca][x]+dis[lca][y]);
	lca = fa[lca][0];
}

至此本题就基本做完了。再汇总一下主要的操作:

  • 预处理出倍增数组fa[][](你要是非要用树剖LCA我不拦着你)
  • 对于每个节点,在把所有边都读入之后Dijkstra,注意是对于每个节点的子树(包括节点本身)跑,所以要判断一下下一个要跑的点是否不在当前根节点的子树里,用之前求fa[][]数组dep[]数组判断一下即可。(跑spfa似乎不行,我也不清楚为什么)

然后代码实现:

#include <iostream>
#include <iomanip>
#include <unordered_map>
#include <queue>
#include <cstring>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define MARK cout << "###"
#define _MARK "@@@"
#define LMARK "!!!~~~"
#define ZY " qwq "
#define _ " "
#define Endl cout << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define ABS(x) (((x) < 0) ? (-(x)) : (x))
#define N 100005
#define M 500005
// #define int long long
#define mod %
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false);cin.tie(NULL), cout.tie(NULL);}
/*
    来改T4
    wy说的很明白,我尝试代码实现
    前n-1条输入的边是树边,所以可以在这里求一个LCA
*/
int n, m, Q, star_cnt;
long long final_ans;
bool vis[N];
int head[N], dep[N], pa[N];
int fa[N][30];
struct star{int v, nxt; long long w;}e[M<<1];
struct node{
    int id;
    long long w;
    friend bool operator < (node A, node B){return A.w > B.w;}// 大于!
};
unordered_map<int, long long> dis[N];// woqu,map能这么用?!O(1)建点?!
priority_queue<node> q;
inline void star_add(int u, int v, long long w){e[++ star_cnt].v=v, e[star_cnt].w=w, e[star_cnt].nxt=head[u], head[u]=star_cnt;}
void get_fa__(int x, int faer){
    int k(0);
    for (; fa[x][k] != 0 ; ++ k)
        fa[x][k+1] = fa[fa[x][k]][k];
    pa[x] = k;
    for (re i = head[x] ; i ; i = e[i].nxt){
        if (e[i].v == faer) continue;
        dep[e[i].v] = dep[x]+1, fa[e[i].v][0] = x;
        get_fa__(e[i].v, x);
    }
}
// 利用递归回溯更新的特性,以及dep数组,求某一个点到他的子树中的点的距离
// 然后
/*random_device seed;
mt19937 myrand(seed());
inline bool comp(node A, node B){return dis[A.x][A.id] < dis[A.x][B.id];}
inline void spfa(int x){
    for (re i = 1 ; i <= n ; ++ i) inq[i] = false, dis[x][i] = 999999999999999999;
    L = 0, R = -1, dis[x][x] = 0, q[++ R] = (node){x, x}; node now;
    while (L <= R){
        now = q[L], L ++, inq[now.id] = false;
        if ( (myrand() / (((long long)(R-L+1)<<10) + 1) / 100 ) == 0) sort(q+L, q+R+1, comp);
        for (re i = head[now.id] ; i ; i = e[i].nxt){
            if (dep[e[i].v] < dep[x]) continue;// 下一个点要是x的子树,那下一个点的深度必须要比x大
            if (dis[x][e[i].v] > dis[x][now.id]+e[i].w){
                dis[x][e[i].v] = dis[x][now.id]+e[i].w;
                // cout << "最短路:" << x << _ << e[i].v << '\n';
                if (inq[e[i].v] == false)
                    q[++ R] = (node){x, e[i].v}, inq[e[i].v] = true;
            }
        }
    }
    // Endl, Endl;
}*/
inline void dijskra(int x){
    // for (re i = 1 ; i <= n ; ++ i) dis[x][i] = 114514191900000, vis[i] = false;
    q.push((node){x, 0}), dis[x][x] = 0; node now;
    while (q.empty() == false){
        now = q.top(), q.pop();
        if (vis[now.id] == true) continue;
        vis[now.id] = true;
        for (re i = head[now.id] ; i ; i = e[i].nxt){
            if (dep[e[i].v] < dep[x]) continue;
            if(vis[e[i].v]==1)continue;
            if (dis[x][e[i].v] > dis[x][now.id]+e[i].w || dis[x][e[i].v] == 0){
                dis[x][e[i].v] = dis[x][now.id]+e[i].w;
                if (vis[e[i].v] == false){
                    q.push((node){e[i].v, dis[x][e[i].v]});
                }
            }
        }
    }
}
void dfs(int x, int faer){
    for (re i = head[x] ; i ; i = e[i].nxt){
        if (e[i].v == faer) continue;
        if (ABS(dep[x]-dep[e[i].v]) > 1) continue;// 返祖边,不搜过去
		// cerr << "dfs: " << x << _ << e[i].v << '\n';
        dfs(e[i].v, x);
    }
    dijskra(x);
    memset(vis, false, sizeof(vis));
}
inline int LCA(int x, int y){
    // cout << x << _ << y << '\n';
    if (dep[x] < dep[y]) swap(x, y);
    // cout << x << _ << y << '\n';
    for (re i = pa[x] ; i >= 0 ; -- i)
        if (dep[fa[x][i]] >= dep[y])
            x = fa[x][i];
    // cout << x << _ << y << '\n';
    if (x == y) return x;
    for (re i = pa[x] ; i >= 0 ; -- i)
        if (fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    // cout << x << _ << y << '\n';
    return fa[x][0];
}
inline void work(){
    cin >> n >> m >> Q;
    for (re i = 1, uu, vv, ww ; i <= n-1 ; ++ i){cin >> uu >> vv >> ww; star_add(uu, vv, ww), star_add(vv, uu, ww);}
    dep[0] = -1; 
    get_fa__(1, 0);
    /* for (re i = 1 ; i <= n ; ++ i){
        for (re j = 0 ; fa[i][j] != 0 ; ++ j)
            cout << i << _ << j << _ << fa[i][j] << '\n';
        Endl;
    }
    for (re i = 1 ; i <= n ; ++ i)
        cout << i << _ << dep[i] << '\n'; */
    for (re i = n, uu, vv, ww ; i <= m ; ++ i){cin >> uu >> vv >> ww; star_add(uu, vv, ww), star_add(vv, uu, ww);}// , cout << "u、v:" << uu << _ << vv << '\n'
    // NIMA读入竟然错了
    dfs(1, 0);
    int uer, ver, lca;
    while (Q --){
        cin >> uer >> ver; lca = LCA(uer, ver), final_ans = 114514191999999999;
        final_ans = MIN(final_ans, dis[lca][uer]+dis[lca][ver]);
        // cout << "LCA: " << lca << '\n';
        // for (; fa[lca][0] != 0 ; lca = fa[lca][0]){
        //     final_ans = MIN(final_ans, dis[lca][uer]+dis[lca][ver]);
        //     // cout << "统计长度:" << lca << _ << uer << _ << ver << _ << dis[lca][uer] << _ << dis[lca][ver] << '\n';
        // }
        while (lca != 0){
            final_ans = MIN(final_ans, dis[lca][uer]+dis[lca][ver]);
            lca = fa[lca][0];
        }
        // Endl;
        cout << final_ans << '\n';
        // Endl, Endl;
    }
}
/*WA成0分,造了数据: 
7 7 3
1 2 1
2 3 4
2 4 5
4 5 6
4 6 7
1 7 2
6 2 1
1 6
7 6
5 6
*/// 只对了1个 // 额不对是我刚才数据搞错了 这个数据过了
// #define IXINGMY
char_phi main(){
    #ifdef IXINGMY
        FBI_OPENTHEDOOR(a);
    #endif
    Fastio_setup();
    work();
    return GMY;
}
posted @   char_phi  阅读(13)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示