首页 > 其他分享 >YC314A [ 20240704 CQYC省选模拟赛 T1 ] 士兵(solider)

YC314A [ 20240704 CQYC省选模拟赛 T1 ] 士兵(solider)

时间:2024-07-04 21:20:42浏览次数:8  
标签:q1 q2 20240704 省选 YC314A int array include define

题意

给定一张 \(n\) 个点 \(m\) 条边的有向图,每条边上有一个字母。

\(q\) 次询问,每次询问 \(s \to t\) 中的最短回文路径的长度是多少。

\(n \le 10 ^ 3, m \le 10 ^ 5\)

Sol

区间 \(\text{dp}\),设 \(f_{i, j}\) 表示从 \(i\) 到 \(j\) 的最短回文路径的长度。

每次枚举一条边 \(l \to i\),以及 \(j \to r\),判断两条边的字母是否相等,暴力转移即可。

直接对于每个点跑一遍 \(\text{bfs}\),复杂度为 \(O(m ^ 2)\)。

考虑优化,将一次过程拆成两次。

设 \(g_{i, j, c}\) 表示从 \(i\) 到 \(j\) 的最短回文路径,且最后一条边为的字母为 \(c\)。

对于一个状态 \(f_{x, y}\),枚举一条出边 \(y \to z\),转移到 \(g_{x, z, c}\) 上。

这样就变成了有两种边的 \(\text{bfs}\),考虑用两个队列来存,这样每次取两个队列中 \(dis\) 较小的即可。

复杂度:\(O(nm + 26n ^ 2)\)

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <tuple>
#include <queue>
#include <vector>
#include <assert.h>
#define pii pair <int, int>
#define tupl tuple <int, int, char>
using namespace std;
#ifdef ONLINE_JUDGE

/* #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) */
/* char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; */

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

#define fi first
#define se second

const int N = 1e3 + 5, M = 1e5 + 5, inf = 1e9 + 7;

char strbuf[2];

array <array <vector <int>, 31>, N> G, T;

queue <pii> q1;
queue <tupl> q2;

array <array <int, N>, N> f;
array <array <pii, N>, N> pref;
array <array <array <int, 31>, N>, N> g;
array <array <array <pii, 31>, N>, N> preg;

void bfs(int n, int m) {
    while (!q1.empty() || !q2.empty()) {
        bool flg1 = q1.empty(), flg2 = q2.empty();
        int u1 = 0, u2 = 0, v1 = 0, v2 = 0, l1 = 0, l2 = 0, c = 0;
        if (!flg1) u1 = q1.front().fi, v1 = q1.front().se, l1 = f[u1][v1];
        if (!flg2) tie(u2, v2, c) = q2.front(), l2 = g[u1][v1][c];
        if (!flg1 && (flg2 || l1 <= l2)) {
            q1.pop();
            c = 0;
            for ( ; c < 26; c++) {
                for (auto k : G[v1][c]) {
 //                   if (v1 == 3 && c == 'm' - 'a')
 //                       cerr << u1 << endl;
                    if (~g[u1][k][c]) continue;
                    g[u1][k][c] = f[u1][v1] + 1;
                    preg[u1][k][c] = make_pair(v1, c);
                    q2.push(make_tuple(u1, k, c));
                }
            }
        }
        else {
            q2.pop();
            for (auto k : T[u2][c]) {
                if (~f[k][v2]) continue;
                f[k][v2] = g[u2][v2][c] + 1;
                pref[k][v2] = make_pair(u2, c);
                q1.push(make_pair(k, v2));
            }
        }
    }
}

array <int, M * 20> ans;

void print(int x, int y, int k, int l, int r) {
    if (x == y) return;
    if (k == -1) {
        ans[l] = pref[x][y].se;
        print(pref[x][y].fi, y, ans[l], l + 1, r);
    }
    else {
        ans[r] = preg[x][y][k].se;
        print(x, preg[x][y][k].fi, -1, l, r - 1);
    }
}

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read(), m = read(), tp = read();
    /* int n = read(), m = read(); */
    for (int i = 0; i <= n; i++) f[i].fill(-1);
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++) g[i][j].fill(-1);
    for (int i = 1; i <= n; i++)
        f[i][i] = 0, q1.push(make_pair(i, i));
    for (int i = 1; i <= m; i++) {
        int x = read(), y = read();
        scanf("%s", strbuf);
        G[x][strbuf[0] - 'a'].push_back(y), T[y][strbuf[0] - 'a'].push_back(x);
        q1.push(make_pair(x, y)), f[x][y] = 1, pref[x][y] = make_pair(x, strbuf[0] - 'a');
    }
    bfs(n, m);
 //   cerr << f[3][5] << endl;
    int q = read();
    while (q--) {
        int x = read(), y = read();
        write(f[x][y]), putchar(32);
       // assert(f[x][y] <= m);
        if (tp == 1 && ~f[x][y]) {
            print(x, y, -1, 1, f[x][y]);
            for (int i = 1; i <= f[x][y]; i++)
                putchar(ans[i] + 'a');
        }
        puts("");
    }
   /*
    int q = read(), x = read(); q--;
    while (q--) {
        int y = read();
        write(f[x][y]), putchar(32);
        assert(f[x][y] <= m);
        if (~f[x][y]) {
            print(x, y, -1, 1, f[x][y]);
            for (int i = 1; i <= f[x][y]; i++)
                putchar(ans[i] + 'a');
        }
        puts("");
        x = y;
    }
    */
    return 0;
}

标签:q1,q2,20240704,省选,YC314A,int,array,include,define
From: https://www.cnblogs.com/cxqghzj/p/18284690

相关文章

  • 程序人生日记20240704|工作零食:米饭+十分米莲藕汁+饼干(减脂记录)
    程序员的工作饮食减脂记录打卡餐别:早餐零食详情:(同事给的不算统计内)零食名称:十分米莲藕汁配饼干其他选择:米饭+海盐饼干。大致热量估算:莲藕汁约50卡,低脂全麦饼干2片约80卡,米饭约500卡,总计约630卡。初始数据:体重:90公斤目标:80公斤完成情况:完成。程序员自律宣言:程序猿不可以......
  • P10218 [省选联考 2024] 魔法手杖 题解
    题目描述:给定序列\(a_1,\cdots,a_n\)和\(b_1,\cdots,b_n\),满足\(a_i\in[0,2^k-1],b_i\ge0\),你需要给出\(S\subseteq\{1,\cdots,n\}\)和\(x\in[0,2^k-1]\)满足:\(\sum\limits_{i\inS}b_i\lem\)。最大化\(val(S,x)=\min\big(\min\limits_{i\inS......
  • YC309A [ 20240627 CQYC省选模拟赛 T1 ] 或(or)
    题意给定一个可重集\(S\),求所有的前缀的集合的代价。定义一个集合的代价为:\[\max_x\left((\max_ib_i\lvertx)-(\min_ib_i\lvertx)\right)\]\(n\le10^6,V\le2\times10^6\)Sol首先看到这个式子直接开划。称较大的数为\(b_i\),较小的数为\(b_j\)。直......
  • YC307B [ 20240625 CQYC省选模拟赛 T2 ] 一个题(ynoi)
    题意你需要维护一个可重集\(S\),支持插入删除以及查询最大的方案使得给定正整数\(k\),划分为\(k\)个非空子集的按位与结果之和最大。\(n\le10^5\)Sol先上个trie。然后考虑一次查询怎么搞。先转化一下,如果需要划分为\(k\)个子集,显然需要合并\(n-k\)次。我们只......
  • 联合省选 2024 游记
    省流:abs(__int128)纯属去体验一下。FJ-S0124,谁都比不上我八倍队线。Day1上场。看T1。这个题目背景咋和题目一点关系都没有。。。盯了一会儿发现可以把\(x,y\)加起来判断就可以了。然后花十分钟码了一个直接枚举答案的,发现答案可能很大,于是开始拆贡献。这里其实已经有想过......
  • Luogu P9542 [湖北省选模拟 2023] 棋圣 alphago
    2023.08.19:修改了一处笔误。手玩发现对于一颗生成树,如果存在至少一个点的度数\(>2\)(即不为链),那么肯定能使得所有棋子都在一条边的两个端点上。因为有度数\(>2\)的点的存在,这里就可以合并与其相连的点的棋子。先考虑非链的情况的答案,记两部分棋子黑白棋子颜色分别为\(c(a/......
  • YC307A [ 20240622 CQYC省选模拟赛 T1 ] 划船(boat)
    题意给定一个有向图\(G\),以及将所有边反向重连的无向图\(T\)。你最多可以在\(T\)上连续走\(k\)条边,走过每条边的代价都为\(1\),然后必须在\(G\)的对应点上走一条边以恢复体力。若当前对应点没有出边,则停留在该点\(1\)代价。求每个点到\(n\)的最小代价。Sol考......
  • 省选训练总结
    目录2024.2.19T1题目大意solutionT2题目大意solution2024.2.20T1T22023.2.22T1题目大意solution2023.2.23T1题目大意solutionT2题目大意solution2024.2.26T1题目大意solutionT2题目大意solutionT3题目大意solution2024.2.27T1题目大意solutionT3题目大意solution2024.2.28补题2024......
  • YC303C [ 20240617 CQYC省选模拟赛 T3 ] Generals(generals)
    题意给定一张\(n\timesm\)的地图。对于第\(0\)列,第\(m+1\)列,第\(0\)行,第\(n+1\)行,有\(2n+2m\)个人,每个人面朝地图中心。每个人走到别人染过色的位置,或走出地图,将走过的地方染色。你需要求出共有多少种本质不同的染色方案。\(n,m\le10^6\)Sol直接......
  • YC302A [ 20240617 CQYC省选模拟赛 T1 ] 构造字符串(string)
    题意你需要构造一个长度为\(n\)的字符串。使得后缀数组为给定的序列\(a\),\(\text{manacher}\)的回文序列为\(b\)。Sol注意到后缀数组实际上是一系列\(\le\)的限制,而\(\text{manacher}\)是一堆相等以及两个不相等的限制。若直接建边很难搞。考虑将限制统一,后缀数组......