CCF-CSP真题《202305-5 闪耀巡航》思路+python,c++满分题解

 想查看其他题的真题及题解的同学可以前往查看:CCF-CSP真题附题解大全

试题编号:202305-5
试题名称:闪耀巡航
时间限制:5.0s
内存限制:512.0MB
问题描述:

问题描述

西西艾弗岛旅游公司最近推出了一系列环绕西西艾弗岛的闪耀游轮航线。普通的航线通常是一条环线,以便乘客在漫长的旅途之后回到出发点;而闪耀航线则多为有惊无险的单程。因此,西西艾弗岛旅游公司也允许乘客自己选择一些能够返回起点的航线组合。具体而言,西西艾弗岛旅游公司推出的航线可以用仅包含小写字母的字符串表示,其中每一种字母代表航线中途经的一个目的地。例如,航线 aqua 表示从 a 出发,途经 q 和 u,最终返回 a 的航线。西西艾弗岛旅游公司目前运营着 N 条这样的航线,分别用字符串 s1,s2,⋯,sN 表示。我们定义,一条航线的长度为相应的字符串长度减 1,如航线 aqua 的长度为 3。

西西艾弗岛旅游公司为了鼓励乘客乘坐其游轮,推出了一项集章活动。乘坐其游轮途经部分目的地(可以是搭乘的航线的起点或终点)时,可以获得一枚印章。我们用字符串 t 表示所有参与集章活动的目的地。当乘客集齐 t 中所有字母对应的印章时,有机会抽取免费住宿豪华酒店等幸运大奖。

为了确定集章活动给公司带来的预期利润,西西艾弗岛旅游公司想知道:对于每条航线 si,从 si 的起点出发搭乘 si 到达 si 的终点,再经过多条航线(可以是 0 条)完成集章后返回 si 的起点,需要乘坐的航线组合的最小总长度。

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 N 和一个字符串 t,保证 1≤N≤105,1≤|t|≤10,且 t 仅包含不重复的小写字母。

接下来 N 行,每行包含一个字符串 si,表示第 i 条航线。保证 2≤|si|≤106,∑i=1N|si|≤106。

输出格式

输出到标准输出中。

输出包含 N 行,每行输出一个正整数表示对应航线组合的最小总长度,或者输出 -1 表示不存在满足要求的航线组合。

样例输入

6 au
aqua
glass
hug
shiny
sparkling
youth

样例输出

3
14
14
14
26
14

样例输入

7 i
nonstop
perfect
rocket
thrilling
train
trapper
tripper

样例输出

16
16
11
-1
16
22
11

子任务

对于 10% 的数据,保证 1≤N≤10,1≤|t|≤5。

对于另外 10% 的数据,保证 1≤N≤1000,|t|=1。

对于另外 20% 的数据,保证 1≤|t|≤5。

对于 100% 的数据,保证 1≤N≤105,1≤|t|≤10,2≤|si|≤106,∑i=1N|si|≤106,si 和 t 仅包含小写字母,且 t 中字母不重复。

真题来源:闪耀巡航

感兴趣的同学可以如此编码进去进行练习提交

c++满分题解:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
 
const LL inf = 1e18;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n;
    string t;
    cin >> n >> t;
    vector<int> id(26, -1);
    int cnt = 0;
    for(auto &i : t){
        id[i - 'a'] = cnt;
        ++ cnt;
    }
    vector<vector<array<int, 3>>> edge(26);
    vector<array<int, 4>> query(n);
    for(int i = 0; i < n; ++ i){
        string s;
        cin >> s;
        int st = s.front() - 'a';
        int ed = s.back() - 'a';
        int sign = 0;
        int len = s.size() - 1;
        for(auto &i : s){
            if (id[i - 'a'] != -1){
                sign |= (1 << id[i - 'a']);
            }
        }
        edge[ed].push_back({st, len, sign});
        query[i] = {st, ed, sign, len};
    }
    int up = (1 << cnt);
    vector<vector<vector<LL>>> dis(26, vector<vector<LL>>(26, vector<LL>(up, inf)));
    for(int i = 0; i < 26; ++ i){
        dis[i][i][up - 1] = 0;
        priority_queue<array<LL, 3>> team;
        team.push({0, i, up - 1});
        while(!team.empty()){
            array<LL, 3> top = team.top();
            team.pop();
            LL distance = -top[0];
            int u = top[1], sign = top[2];
            if (dis[i][u][sign] != distance)
                continue;
            for(auto &e : edge[u]){
                int v = e[0], len = e[1], si = e[2];
                int nxtsign = (sign ^ (sign & si));
                if (dis[i][v][nxtsign] > distance + len){
                    dis[i][v][nxtsign] = distance + len;
                    team.push({-dis[i][v][nxtsign], v, nxtsign});
                }
            }
        }
    }
    for(int i = 0; i < n; ++ i){
        LL ans = inf;
        int sign = query[i][2];
        for(int s = sign; s; s = (s - 1) & sign)
            ans = min(ans, dis[query[i][0]][query[i][1]][s]);
        ans = min(ans, dis[query[i][0]][query[i][1]][0]);
        if (ans == inf)
            ans = -1;
        else 
            ans += query[i][3];
        cout << ans << '\n';
    }
 
    return 0;
}

 运行结果:

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年12月11日
下一篇 2023年12月11日

相关推荐