2022杭电多校5
1003 C Slipper
题意:给定一颗树,起点和终点,树上路径有变权。存在一种特殊的路径当且仅当深度为x的节点可以花费p点代价到深度为x+k或者x-k的节点上,求最短距离
分析:
单源最短路 关键在于建图
想到给每个深度建点 如果每层建立一个点 相差k层的点就能到达
但是此时有个问题 可能会有同层点需要相互到达
怎么办呢?
肯定不能每个点都建边 会超时超内存
每层建立两个点 出点和入点
这样巧妙的解决了同层互相到达的情况!!!
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef pair<long long, int> PII;
const int N = 4e6 + 10, M = 2 * N , INF = 0x3f3f3f3f;
int h[N], e[M], ne[M], w[M], idx;
long long dist[N];
int depth[N];
vector<int> v[N];
int k, p, S, T, n;
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u, int fa)
{
depth[u] = depth[fa] + 1;
v[depth[u]].push_back(u);
for(int i = h[u]; ~i ; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
dfs(j, u);
}
}
int in(int u)
{
return u + n;
}
int out(int u)
{
return u + n * 2;
}
void dijkstra()
{
priority_queue<PII, vector<PII> ,greater<PII> > q;
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[S] = 0;
q.push({dist[S], S});
while(q.size())
{
auto t = q.top();
q.pop();
int ver = t.second;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; ~i ; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
q.push({dist[j], j});
}
}
}
}
void solve()
{
memset(h, -1, sizeof h), idx = 0;
cin >> n;
for(int i = 1 ; i <= n ; i ++ ) v[i].clear();
for(int i = 1 ; i < n ; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
cin >> k >> p >> S >> T;
dfs(1, 0);
for(int i = 1 ; i <= n ; i ++ )
{
for(auto item : v[i]) // 深度为i的节点,进入深度为i的管道
{
add(item, out(i), 0);
add(in(i), item, 0);
}
if(i - k > 0) add(out(i), in(i - k), p);
if(i + k <= n) add(out(i), in(i + k), p);
}
dijkstra();
cout << dist[T] << '\n';
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
int T = 1;
cin >> T;
while(T -- ) solve();
return 0;
}
1010 J Bragging Dice
题意:
喝酒时候的摇骰子游戏,每个人有n个骰子,随机摇到任意点数。某一个人先手他会说某一个数,再说这个数有几个。这个数量代表两个人骰子的数字总和。
如果后手不相信,可以挑战他,开骰。如果数量符合那么挑战者失败,否则挑战成功。
分析:
可以说没有去酒吧玩过这个游戏的人 读懂题目都很难
因为两个人都知道对方的骰子数目,因此其实按照普通规则是先手必胜的。
但是有一个特殊规则,如果一个人手里的骰子的数每个都不一样,则他所有数都为0。
因此如果两个人都出现了这个情况,则一个数都没有。先手不能说0个数,因此他说什么都是输。
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 200010;
int n;
int a[N], b[N];
int cnta[6], cntb[6];
void solve() {
cin >> n;
for (int i = 1; i <= 6; i++) cnta[i] = cntb[i] = 0;
bool f = false;
for (int i = 1; i <= n; i++) cin >> a[i], cnta[a[i]]++;
for (int i = 1; i <= n; i++) cin >> b[i], cntb[b[i]]++;
for (int i = 1; i <= 6; i++)
if (cnta[i] > 1 || cntb[i] > 1)
f = true;
cout << (f ? "Win!\n" : "Just a game of chance.\n");
}
signed main() {
cin.tie(0)->sync_with_stdio(false);
int T;
cin >> T;
while (T--) solve();
return 0;
}
1012 L Buy Figurines
题意:
排队问题。有n个人来买东西,已知每个人来的时间和购买需要的时间,一共有m个窗口。每个人都会优先选择人少且编号较少的窗口。请问从开始到最后一
个人离开一共花费多久。
分析:
模拟 维护m个窗口的最小值 用到线段树
用优先队列维护一下每个人离开的时间
当轮到一个新的人排队时 只要将已经离开的人减去[线段树单点修改]
每个人离开的时候需要 max(leave[pos],start)+len
表示该人排到pos窗口 但是 不是他想排就马上排到 而是还要保证pos窗口前面的人已经排完
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
#define int long long
#define NO {puts("NO") ; return ;}
#define YES {puts("YES") ; return ;}
#define please return
#define ac 0
typedef pair<int, int> PII;
const int N = 2e6 + 10 , INF = 0x3f3f3f3f;
int n, m, a[N];
int leave[N];
struct Tree
{
int l, r;
int pos, minv; // 排队人最少的位置 / 最少的人数
}tr[N << 2];
struct Node
{
int start, len;
bool operator < (const Node &t) const
{
return start < t.start; // 按照到达时间排序
}
}p[N];
void pushup(int u)
{
tr[u].minv = min(tr[u << 1].minv, tr[u << 1 | 1].minv); // pushup维护pos
if(tr[u << 1].minv == tr[u].minv) tr[u].pos = tr[u << 1].pos; // 注意 在选择人数少的前提下选择编号较小的
else tr[u].pos = tr[u << 1 | 1].pos;
}
void build(int u, int l, int r)
{
tr[u] = {l, r, l, 0};
if(l == r) return ;
else
{
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int v)
{
if(x == tr[u].l && x == tr[u].r)
{
tr[u].minv += v;
}
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u << 1, x, v);
if(x > mid) modify(u << 1 | 1, x, v);
pushup(u);
}
}
void solve()
{
cin >> n >> m;
for(int i = 1 ; i <= n ; i ++ )
{
int a, b;
cin >> a >> b;
p[i] = {a, b};
}
for(int i = 1 ; i <= m ; i ++ ) leave[i] = 0; // 每个人离开的时间
build(1, 1, m);
priority_queue<PII, vector<PII> , greater<PII> > q;
sort(p + 1, p + n + 1);
int ans = 0;
for(int i = 1 ; i <= n ; i ++ )
{
while(q.size() && q.top().first <= p[i].start)
{
modify(1, q.top().second, -1); // 这些人已经离开了
q.pop();
}
int pos = tr[1].pos;
modify(1, pos, 1); // pos排进一个人
leave[pos] = max(p[i].start, leave[pos]) + p[i].len; // 计算每个人离开的时间 排队或者直接开始买
q.push({leave[pos], pos}); // 离开时时间 / 所在窗口
ans = max(leave[pos], ans); // 更新答案
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0);
int T = 1;
cin >> T;
while(T -- ) solve();
please ac;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2019-09-27 绵阳东辰国际test201909.27
2019-09-27 浅谈主席树模板