Loading

P8817 [CSP-S 2022] 假期计划 题解

思路

看一眼数据范围。

发现是一道 \(O(n^2)\) 可做题。

由于题目中路径的长度只有 \(4\) 个点,可以从这一方面继续入手。

考虑预处理。

我们设 \(dp_i,j\) 为从 \(1\)\(x\) 再从 \(x\)\(i\) 这样一条合法路径第 \(j\) 大的权值。

容易发现我们最多只需要处理出前四大的即可,因为需要不同的四个点。

这样,我们就相当于有了 \(\text{C}\) 点和 \(\text{D}\) 点后,我们可以直接得到 \(A\) 点和 \(B\) 点。

复杂度:\(O(n^2)\)

有一个小细节,由于这道题的合法路径判断需要知道两点之间的距离,即全源最短路。

发现边权全部是一可以直接 \(\text{bfs}\) 处理出来。

但是我考场上不知道为什么没有想到写了一个全源最短路。

所以考场代码就变为了:\(O(n^2\log n)\) 的劣复杂度。

\(2500\) 应该问题不大。

Code

放一个考场代码。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2510;

int n , m , cnt , ans , f[N][4][2];
int k , s[N] , vis[N] , head[N] , dis[N][N];

struct edge
{
    int to , nxt , val;
}e[100000];

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

inline void add(int x , int y)
{
    e[++cnt] = {y , head[x] , 1} , head[x] = cnt;
    e[++cnt] = {x , head[y] , 1} , head[y] = cnt;
}

inline void dij(int s)
{
    priority_queue<pair<int , int> , vector<pair<int , int> > , greater<pair<int , int> > > q;
    q.push({0 , s}) , memset(dis[s] , 0x3f , sizeof dis[s]);
    dis[s][s] = 0 , memset(vis , 0 , sizeof vis);
    while(q.empty() == 0)
    {
        int x = q.top().second; q.pop();
        vis[x] = 1;
        for(int i = head[x];i;i = e[i].nxt)
        {
            if(dis[s][e[i].to] > dis[s][x] + e[i].val)
            {
                dis[s][e[i].to] = dis[s][x] + e[i].val;
                if(!vis[e[i].to]) q.push({dis[s][e[i].to] , e[i].to});
            }
        }
    }
}

inline bool check(int x , int y , int z)
{
    int dis1 = dis[x][y] - 1;
    int dis2 = dis[y][z] - 1;
    return dis1 <= k && dis2 <= k;
}

inline bool check(int x , int y , int z , int u)
{
    return (x != y && y != z && z != u && x != z && x != u && y != u);
}

inline void add(int x , int z , int id)
{
    int flag = 4;
    for(int i = 0;i < 4;i++)
        if(f[x][i][1] < z)
            { flag = i; break; }
    if(flag != 4)
    {
        for(int i = 3;i > flag;i--)
            swap(f[x][i][1] , f[x][i - 1][1]),
            swap(f[x][i][0] , f[x][i - 1][0]);
        f[x][flag][1] = z , f[x][flag][0] = id;
    }
}

signed main()
{
    n = read() , m = read() , k = read();
    for(int i = 2;i <= n;i++)
        s[i] = read();
    for(int i = 1;i <= m;i++)
    {
        int x = read() , y = read();
        add(x , y);
    }
    for(int i = 1;i <= n;i++)
        dij(i);
    for(int i = 2;i <= n;i++)
        for(int j = 2;j <= n;j++)
        {
            if(i == j) continue;
            if(check(1 , i , j))
                add(j , s[i] , i);
        }
    memset(vis , 0 , sizeof vis);
    for(int i = 2;i <= n;i++)
        for(int j = 2;j <= n;j++)
            if(i != j && dis[i][j] - 1 <= k)
            {
                int sum = 0;
                for(int k1 = 0;k1 <= 3;k1++)
                {
                    if(!f[i][k1][0]) continue;
                    for(int k2 = 0;k2 <= 3;k2++)
                    {
                        if(!f[j][k2][0]) continue;
                        if(check(i , j , f[i][k1][0] , f[j][k2][0]))
                            sum = max(sum , s[i] + s[j] + f[i][k1][1] + f[j][k2][1]);
                    }
                }
                ans = max(ans , sum);
            }
    cout << ans << endl;
    return 0;
}

\(\text{bfs}\) 也放一个吧。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2510;

int n , m , cnt , ans , f[N][4][2];
int k , s[N] , vis[N] , head[N] , dis[N][N];

struct edge
{
    int to , nxt , val;
}e[100000];

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

inline void add(int x , int y)
{
    e[++cnt] = {y , head[x] , 1} , head[x] = cnt;
    e[++cnt] = {x , head[y] , 1} , head[y] = cnt;
}

inline void bfs(int s)
{
    queue<int> q;
    memset(dis[s] , 0x3f , sizeof dis[s]);
    q.push(s) , dis[s][s] = 0;
    while(q.empty() == 0)
    {
        int x = q.front(); q.pop();
        for(int i = head[x];i;i = e[i].nxt)
            if(dis[s][e[i].to] == 0x3f3f3f3f3f3f3f3f)
                dis[s][e[i].to] = dis[s][x] + e[i].val,
                q.push(e[i].to);
    }
}

inline bool check(int x , int y , int z)
{
    int dis1 = dis[x][y] - 1;
    int dis2 = dis[y][z] - 1;
    return dis1 <= k && dis2 <= k;
}

inline bool check(int x , int y , int z , int u)
{
    return (x != y && y != z && z != u && x != z && x != u && y != u);
}

inline void add(int x , int z , int id)
{
    int flag = 4;
    for(int i = 0;i < 4;i++)
        if(f[x][i][1] < z)
            { flag = i; break; }
    if(flag != 4)
    {
        for(int i = 3;i > flag;i--)
            swap(f[x][i][1] , f[x][i - 1][1]),
            swap(f[x][i][0] , f[x][i - 1][0]);
        f[x][flag][1] = z , f[x][flag][0] = id;
    }
}

signed main()
{
    n = read() , m = read() , k = read();
    for(int i = 2;i <= n;i++)
        s[i] = read();
    for(int i = 1;i <= m;i++)
    {
        int x = read() , y = read();
        add(x , y);
    }
    for(int i = 1;i <= n;i++)
        bfs(i);
    for(int i = 2;i <= n;i++)
        for(int j = 2;j <= n;j++)
        {
            if(i == j) continue;
            if(check(1 , i , j))
                add(j , s[i] , i);
        }
    memset(vis , 0 , sizeof vis);
    for(int i = 2;i <= n;i++)
        for(int j = 2;j <= n;j++)
            if(i != j && dis[i][j] - 1 <= k)
            {
                int sum = 0;
                for(int k1 = 0;k1 <= 3;k1++)
                {
                    if(!f[i][k1][0]) continue;
                    for(int k2 = 0;k2 <= 3;k2++)
                    {
                        if(!f[j][k2][0]) continue;
                        if(check(i , j , f[i][k1][0] , f[j][k2][0]))
                            sum = max(sum , s[i] + s[j] + f[i][k1][1] + f[j][k2][1]);
                    }
                }
                ans = max(ans , sum);
            }
    cout << ans << endl;
    return 0;
}
posted @ 2022-11-01 14:10  JiaY19  阅读(529)  评论(0编辑  收藏  举报