EOJ Monthly 2021.2 部分分题解
因为暂时实在想不出为什么错,所以暂时放部分分的题解,之后明白了再补上(codeforces的题还没补完要先补那个qwq)
A. 昔我往矣(得分:7)
题目
思路
这题就嫖了子任务1的7分,没有什么思路,,,
子任务1直接输出所有边权的和就行了,因为只有5个点4条边,每一条都必然经过。
代码
略,,完全是骗的分,等我搞懂了再加上正确的代码。
B. 杨柳依依(得分:74)
题目
思路
很巧,这场比赛前正在纠结天梯赛的一道题: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)
题目
思路
本来奔着水23分的目的去的,写的很暴力,结果拿了67分,有、、惊讶。剩下的部分TLE,大概是我的方法实在不行。
大概思路:
- 维护 0 0 0 ~ n − 1 n - 1 n−1 每个数字可能出现范围 [ l , r ] [l,r] [l,r] ;
- 维护数组 a a a (即排列 p p p)中每个元素 a i a_i ai 的最小值。
- 最后看 0 0 0 ~ n − 1 n - 1 n−1 每个数字是否都能在 [ 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,那么:
- 数字 2 2 2 的出现范围: [ 2 , 3 ] [2,3] [2,3]
- 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ù)雪霏霏(挖坑)
题目
思路
暂无,写了一个纯暴力T了,一分没有,先挖坑。
总结
这可能是到现在为止在发挥上最好的一次,不是说分数排名好,就是能做的题都做出来了,甚至有点超过我对自己能力的预期(原本以为自己会爆零的)。
但是昨天掉回解放前的cf还没补,所以这里就先挖个坑了,等cf补完再来。
多多包涵,共同进步。