EOJ Monthly 2021.2 部分分题解(后期更新)

EOJ Monthly 2021.2 部分分题解

因为暂时实在想不出为什么错,所以暂时放部分分的题解,之后明白了再补上(codeforces的题还没补完要先补那个qwq)

A. 昔我往矣(得分:7)

题目

A. 昔我往矣

思路

这题就嫖了子任务1的7分,没有什么思路,,,

子任务1直接输出所有边权的和就行了,因为只有5个点4条边,每一条都必然经过。

代码

略,,完全是骗的分,等我搞懂了再加上正确的代码。


B. 杨柳依依(得分:74)

题目

B. 杨柳依依

思路

很巧,这场比赛前正在纠结天梯赛的一道题:L2-001 紧急救援 (25 分)(srds我这题还有一半的点还没过呜呜呜)

和这题很像,基本思路是 dijstra + 路径还原。一般的路径还原中,我们用 pre​ 数组来记录前驱节点的位置;这题中,由于若一个人从起点到终点有不同的路可走,则每个点经过的概率不同,所以需要记录所有可行的路径。因此我们将 pre 数组改成邻接表(用vector实现), pre[i] 中的任意一点 x x x 表示从 x x x i i i 点,是从起点 s s s i i i 的最短路径。(这部分理解了dijtra的原理应该能明白)

至于概率部分,在我们构建完邻接表 pre​ 之后,从终点向起点递归增加每个点的概率。最开始的终点,概率增加 1 1 1;终点的前驱节点则每个节点增加 1.0 / pre[i].size() 的概率,以此类推。下图为递归过程:

在这里插入图片描述

但是很可惜,我最后还是WA了一个点,就 一 个 点 其 他 全 对。

悲伤的故事

如果有大佬知道这可能是什么原因的错误的话,麻烦告诉我ww

代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e4 + 19;
const ll mod = 1e9 + 7;
const double eps = 1e-5;

struct node
{
    int v, dist;
    node(){}
    node(int vv, int dd){v = vv; dist = dd;}
    bool operator < (const node& a) const
    {
        if(dist == a.dist)
        {
            return v < a.v;
        }
        return dist > a.dist;
    }
};

vector<node> vec[N];
int dis[N];
double num[N];
vector<int> pre[N];
int n, m, s, d;

void dij(int s)
{
    for(int i = 0; i < n; i++)
    {
        pre[i].clear();
    }
    fill(dis, dis + n + 1, INF);
    dis[s] = 0;
    priority_queue<node> que;
    que.push(node(s, 0));
    while(!que.empty())
    {
        node x = que.top();
        que.pop();
        for(int i = 0; i < vec[x.v].size(); i++)
        {
            node y = vec[x.v][i];
            if(dis[y.v] > x.dist + y.dist)
            {
                dis[y.v] = x.dist + y.dist;
                pre[y.v].clear();
                pre[y.v].push_back(x.v);
                que.push(node(y.v, dis[y.v]));
            }
            else if(dis[y.v] == x.dist + y.dist)
            {
                pre[y.v].push_back(x.v);
            }
        }
    }
}

void func(int t, double p)
{
    num[t] += p;
    if(pre[t].size() == 0)
    {
        return ;
    }
    p /= (double)pre[t].size();
    for(int i = 0; i < pre[t].size(); i++)
    {
        func(pre[t][i], p);
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < m; i++)
    {
        int u, v;
        cin >> u >> v;
        vec[u].push_back(node(v, 1));
        vec[v].push_back(node(u, 1));
    }
    int k;
    cin >> k;
    while(k--)
    {
        int a, b;
        cin >> a >> b;
        dij(a);
        func(b, 1.0);
    }
    int maxi = 0;
    double maxx = 0;
    for(int i = 0; i < n; i++)
    {
        if(num[i] > maxx)
        {
            maxx = num[i];
            maxi = i;
        }
    }
    cout << maxi << endl;
    return 0;
}

C. 今我来思(sì)(得分:67)

题目

C. 今我来思(sì)

思路

本来奔着水23分的目的去的,写的很暴力,结果拿了67分,有、、惊讶。剩下的部分TLE,大概是我的方法实在不行。

大概思路:

  1. 维护 0 0 0 ~ n − 1 n - 1 n1 每个数字可能出现范围 [ l , r ] [l,r] [l,r]
  2. 维护数组 a a a (即排列 p p p)中每个元素 a i a_i ai 的最小值。
  3. 最后看 0 0 0 ~ n − 1 n - 1 n1 每个数字是否都能在 [ l , r ] [l,r] [l,r] 范围内找到家。

思路1维护时取并集,思路2维护时取最大。举例, m i n [ 1 , 3 ] = 2 ,   m i n [ 2 , 4 ] = 2 min[1,3] = 2, \ min[2,4] = 2 min[1,3]=2, min[2,4]=2,那么:

  1. 数字 2 2 2 的出现范围: [ 2 , 3 ] [2,3] [2,3]
  2. m i n [ 1 , 4 ] = 2 min[1,4] = 2 min[1,4]=2,从 a 1 a_1 a1 a 4 a_4 a4 的值都不小于 2 2 2 (但是如果 a 3 a_3 a3 不小于 3 3 3 a 3 a_3 a3 还是不小于3,即取最大)

但是这样计算只能拿67分,之后的都会超时。

代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e5 + 19;
const ll mod = 1e9 + 7;

int a[N];
bool vis[N];
struct node
{
    int l, r;
    bool vis = 0;
} vec[N];


int main()
{
    int n, q;
    cin >> n >> q;
    fill(a, a + n + 1, -1);
    for(int i = 0; i < n; i++)
    {
        vec[i].l = 0;
        vec[i].r = n - 1;
    }
    bool flag = 0;
    while(q--)
    {
        int l, r, x;
        cin >> l >> r >> x;
        for(int i = l; i <= r; i++)
        {
            a[i] = max(a[i], x);
        }
        vec[x].l = max(vec[x].l, l);
        vec[x].r = min(vec[x].r, r);
        vec[x].vis = 1;
    }
    for(int i = n - 1; i >= 0; i--)
    {
        if(vec[i].vis == 0)
        {
            continue;
        }
        flag = 1;
        for(int j = vec[i].l; j <= vec[i].r; j++)
        {
            if(a[j] > i)
                continue;
            flag = 0;
            a[j] = i;
        }
        if(flag)
            break;
    }
    if(flag)
    {
        for(int i = 0; i < n; i++)
        {
            cout << -1;
            if(i != n - 1)
                cout << ' ';
        }
    }
    else
    {
        for(int i = 0; i < n; i++)
        {
            flag = 1;
            int k = 0;
            for(int j = vec[i].l; j <= vec[i].r; j++)
            {
                if(vis[j] || a[j] > i)
                    continue;
                flag = 0;
                k = j;
                if(a[j] == i)
                {
                    break;
                }
            }
            if(flag)
                break;
            vis[k] = 1;
            a[k] = i;
        }
        if(flag)
        {
            for(int i = 0; i < n; i++)
            {
                cout << -1;
                if(i != n - 1)
                    cout << ' ';
            }
        }
        else
        {
            for(int i = 0; i < n; i++)
            {
                cout << a[i];
                if(i != n - 1)
                    cout << ' ';
            }
        }
    }
    cout << endl;
    return 0;
}

D. 雨(yù)雪霏霏(挖坑)

题目

D. 雨(yù)雪霏霏

思路

暂无,写了一个纯暴力T了,一分没有,先挖坑。


总结

这可能是到现在为止在发挥上最好的一次,不是说分数排名好,就是能做的题都做出来了,甚至有点超过我对自己能力的预期(原本以为自己会爆零的)。

但是昨天掉回解放前的cf还没补,所以这里就先挖个坑了,等cf补完再来。

多多包涵,共同进步。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值