【USACO 2021 January Contest, Platinum】Problem 1. Sum of Distances
\(\text{Solution}\)
一个性质:两个 \(K\) 元组有边相连当且仅当每个点在对应的图中到 \(1\) 有奇偶性相同的路径
那么我们就可以预处理每个图中的点到 \(1\) 的奇偶最短路
再考虑路径长度,显然是 \(\min(\max_{i=1}^k{odd_i}, \max_{i=1}^k{even_i})\)
把它拆开 \(\max_{i=1}^k{odd_i} + \max_{i=1}^k{even_i} - \max_{i=1}^k(\max(odd_i,even_i))\)
那么一个点的信息就成了三个
分别算出这三个 \(\max\) 即可
先枚举 \(\max\) 即最大的是多少,那么 \(K\) 元组其他位置就是其他图中小于 \(\max\) 的点的个数乘起来
可以从大枚举 \(\max\),把点信息为 \(\max\) 先算了,再删去这个点即可,那么就用线段树维护区间积即可,线段树下标表示第 \(i\) 个图剩余点的个数
好处是线段树中剩余的点信息一定小于等于当前枚举的 \(\max\),避免既要处理图不同又要处理信息大小关系的困境
\(\text{Code}\)
#include <cstdio>
#include <queue>
#include <vector>
#include <iostream>
#include <cstring>
#define re register
#define LL long long
using namespace std;
const int K = 5e4 + 5, N = 2e5 + 5, INF = 0x3f3f3f3f;
LL MOD = 1e9 + 7;
int mx, k, n, m, h[N], tot, total, dis[N][2], col[N], vis[N][2];
vector<int> g[N][3];
struct node{int x, z;};
queue<node> Q;
struct edge{int to, nxt;}e[N << 1];
inline void add(int x, int y)
{
e[++tot] = edge{y, h[x]}, h[x] = tot;
e[++tot] = edge{x, h[y]}, h[y] = tot;
}
inline void read(int &x)
{
x = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
}
struct Segment{
#define ls (p << 1)
#define rs (ls | 1)
int tr[K << 2]; LL sum[K << 2];
void build(int p, int l, int r)
{
if (l == r) return void(sum[p] = 0);
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
void update(int p, int l, int r, int x, int v)
{
if (x < l || x > r) return;
if (l == r) return void(sum[p] += v);
int mid = (l + r) >> 1;
if (x <= mid) update(ls, l, mid, x, v);
else update(rs, mid + 1, r, x, v);
sum[p] = sum[ls] * sum[rs] % MOD;
}
LL query(int p, int l, int r, int tl, int tr)
{
if (tl > r || tr < l) return 1;
if (tl <= l && r <= tr) return sum[p];
int mid = (l + r) >> 1;
LL res = 1;
if (tl <= mid) res = query(ls, l, mid, tl, tr);
if (tr > mid) res = res * query(rs, mid + 1, r, tl, tr) % MOD;
return res;
}
}T;
inline void spfa()
{
for(re int j = 1; j <= n; j++) dis[j][0] = dis[j][1] = INF, vis[j][0] = vis[j][1] = 0;
dis[1][0] = 0, vis[1][0] = 1, Q.push(node{1, 0});
while (!Q.empty())
{
node now = Q.front(); Q.pop();
for(re int j = h[now.x]; j; j = e[j].nxt)
if (dis[e[j].to][now.z ^ 1] > dis[now.x][now.z] + 1)
{
dis[e[j].to][now.z ^ 1] = dis[now.x][now.z] + 1;
if (!vis[e[j].to][now.z ^ 1])
vis[e[j].to][now.z ^ 1] = 1, Q.push(node{e[j].to, now.z ^ 1});
}
vis[now.x][now.z] = 0;
}
}
inline LL solve(int z)
{
T.build(1, 1, k);
for(re int i = mx; i >= 0; i--)
for(re int j = 0; j < g[i][z].size(); j++) T.update(1, 1, k, col[g[i][z][j]], 1);
LL res = 0;
for(re int i = mx; i; i--)
for(re int j = 0; j < g[i][z].size(); j++)
{
int now = g[i][z][j];
res = (res + T.query(1, 1, k, 1, col[now] - 1) * T.query(1, 1, k, col[now] + 1, k) % MOD * i % MOD) % MOD;
T.update(1, 1, k, col[now], -1);
}
return res;
}
int main()
{
read(k);
for(re int i = 1; i <= k; i++)
{
tot = 0;
read(n), read(m);
for(re int j = 1, x, y; j <= m; j++) read(x), read(y), add(x, y);
spfa();
for(re int j = 1; j <= n; j++)
{
col[total + j] = i;
for(re int l = 0; l <= 1; l++)
if (dis[j][l] ^ INF) g[dis[j][l]][l].push_back(total + j);
if (max(dis[j][0], dis[j][1]) ^ INF) g[max(dis[j][0], dis[j][1])][2].push_back(total + j);
if (dis[j][0] ^ INF) mx = max(mx, dis[j][0]);
if (dis[j][1] ^ INF) mx = max(mx, dis[j][1]);
}
total += n;
for(re int i = 1; i <= n; i++) h[i] = 0;
}
printf("%lld\n", (solve(0) + solve(1) - solve(2) + MOD) % MOD);
}
当然用 \(STL\) 的 \(vector\) 和 \(queue\) 虽然直观但终究是慢了
\(\text{Code}\)
#include <cstdio>
#include <iostream>
#define re register
#define LL long long
using namespace std;
const int K = 5e4 + 5, N = 2e5 + 5, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int mx, k, n, m, h[N], tot, total, dis[N][2], col[N], vis[N][2], g[N][3], Tot;
struct node{int x, z;};
node Q[N << 1];
struct edge{int to, nxt;}e[N << 1], E[N << 1];
inline void add(int x, int y)
{
e[++tot] = edge{y, h[x]}, h[x] = tot;
e[++tot] = edge{x, h[y]}, h[y] = tot;
}
inline void Add(int x, int z, int y){E[++Tot] = edge{y, g[x][z]}, g[x][z] = Tot;}
inline void read(int &x)
{
x = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
}
struct Segment{
#define ls (p << 1)
#define rs (ls | 1)
int tr[K << 2], sum[K << 2];
void build(int p, int l, int r)
{
if (l == r) return void(sum[p] = 0);
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
void update(int p, int l, int r, int x, int v)
{
if (x < l || x > r) return;
if (l == r) return void(sum[p] += v);
int mid = (l + r) >> 1;
if (x <= mid) update(ls, l, mid, x, v);
else update(rs, mid + 1, r, x, v);
sum[p] = 1LL * sum[ls] * sum[rs] % MOD;
}
int query(int p, int l, int r, int tl, int tr)
{
if (tl > r || tr < l) return 1;
if (tl <= l && r <= tr) return sum[p];
int mid = (l + r) >> 1;
int res = 1;
if (tl <= mid) res = query(ls, l, mid, tl, tr);
if (tr > mid) res = 1LL * res * query(rs, mid + 1, r, tl, tr) % MOD;
return res;
}
}T;
inline void spfa()
{
int head = 0, tail = 1;
for(re int j = 1; j <= n; j++) dis[j][0] = dis[j][1] = INF, vis[j][0] = vis[j][1] = 0;
dis[1][0] = 0, vis[1][0] = 1, Q[1] = node{1, 0};
while (head < tail)
{
node now = Q[++head];
for(re int j = h[now.x]; j; j = e[j].nxt)
if (dis[e[j].to][now.z ^ 1] > dis[now.x][now.z] + 1)
{
dis[e[j].to][now.z ^ 1] = dis[now.x][now.z] + 1;
if (!vis[e[j].to][now.z ^ 1])
vis[e[j].to][now.z ^ 1] = 1, Q[++tail] = node{e[j].to, now.z ^ 1};
}
vis[now.x][now.z] = 0;
}
}
inline int solve(int z)
{
T.build(1, 1, k);
for(re int i = mx; i >= 0; i--)
for(re int j = g[i][z]; j; j = E[j].nxt) T.update(1, 1, k, col[E[j].to], 1);
int res = 0;
for(re int i = mx; i; i--)
for(re int j = g[i][z]; j; j = E[j].nxt)
res = (res + 1LL * T.query(1, 1, k, 1, col[E[j].to] - 1) * T.query(1, 1, k, col[E[j].to] + 1, k) % MOD * i % MOD) % MOD,
T.update(1, 1, k, col[E[j].to], -1);
return res;
}
int main()
{
read(k);
for(re int i = 1; i <= k; i++)
{
tot = 0;
read(n), read(m);
for(re int j = 1, x, y; j <= m; j++) read(x), read(y), add(x, y);
spfa();
for(re int j = 1; j <= n; j++)
{
col[total + j] = i;
for(re int l = 0; l <= 1; l++)
if (dis[j][l] ^ INF) Add(dis[j][l], l, total + j);
if (max(dis[j][0], dis[j][1]) ^ INF) Add(max(dis[j][0], dis[j][1]), 2, total + j);
if (dis[j][0] ^ INF) mx = max(mx, dis[j][0]);
if (dis[j][1] ^ INF) mx = max(mx, dis[j][1]);
}
total += n;
for(re int i = 1; i <= n; i++) h[i] = 0;
}
printf("%d\n", (1LL * solve(0) + solve(1) - solve(2) + MOD) % MOD);
}
【USACO 2021 January Contest, Platinum】Problem 1. Sum of Distances的更多相关文章
- 孤独的照片【USACO 2021 December Contest Bronze】
孤独的照片 Farmer John 最近购入了 \(N\) 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一. 奶牛目前排成一排,Farmer John 想要为 ...
- 洛谷 P2812 校园网络【[USACO]Network of Schools加强版】 解题报告
P2812 校园网络[[USACO]Network of Schools加强版] 题目背景 浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件.但是 ...
- 【USACO 2019 Feburary Contest】Gold
模拟二月金组,三个半小时AK. USACO 2019 Feburary Contest, Gold T1 题意:给定一棵树,每个点有点权,每次可以进行以下操作之一: 更改一个点的点权 求某条路径上的点 ...
- USACO 2015 December Contest, Platinum Problem Max Flow【树链剖分】
题意比较难理解,就是给你n个点的树,然后给你m个修改操作,每一次修改包括一个点对(x, y),意味着将x到y所有的点权值加一,最后问你整个树上的点权最大是多少. 比较裸的树链剖分了,感谢Haild的讲 ...
- USACO 2023 January Contest, Bronze Problem 3. Moo Operations
这道题目灰常简单,我们先从最简单的3个字符串开始 有以下几种情况: 可以看到,只有在中间是O的情况下才有可能变成MOO 辣么我们不妨在在s串中枚举这个中间 O 每枚举到一个就看看能不能用他的本身操作次 ...
- 【 2013 Multi-University Training Contest 3 】
HDU 4622 Reincarnation 枚举字符串的起点,构造后缀自动机,每次插入一个字符,就能统计得到当前不同字串的个数,预处理出所有的询问. #include<cstdio> # ...
- 【贪心+中位数】【新生赛3 1007题】 Problem G (K)
Problem G Time Limit : 4000/2000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Sub ...
- USACO 2016 January Contest, Gold解题报告
1.Angry Cows http://www.usaco.org/index.php?page=viewproblem2&cpid=597 dp题+vector数组运用 将从左向右与从右向左 ...
- 【 2013 Multi-University Training Contest 8 】
HDU 4678 Mine 对于每个空白区域,求SG值. 最后异或起来等于0,先手必败. #pragma comment(linker,"/STACK:102400000,102400000 ...
- 【 2013 Multi-University Training Contest 7 】
HDU 4666 Hyperspace 曼哈顿距离:|x1-x2|+|y1-y2|. 最远曼哈顿距离,枚举x1与x2的关系以及y1与y2的关系,取最大值就是答案. #include<cstdio ...
随机推荐
- Day26:内部类的详解
内部类 1.1内部类概述 内部类:就是在一个类中定义另外一个类. 例如我们在A类中定义一个B类,那么B类就是A类的内部类,A则是B的外部类. 好比我们的手机是一个类,而手机内部的零件又属于一个类. 内 ...
- 漫谈计算机网络: 运输层 ------ 从UDP ->TCP , 从面向通信->面向用户,三次握手/四次挥手?
面试答不上?计网很枯燥? 听说你学习 计网 每次记了都会忘? 不妨抽时间和我一起多学学它 深入浅出,用你的空闲时间来探索计算机网络的硬核知识! 博主的上篇连载文章<初识图像处理技术> 图像 ...
- 零基础学习python的第一天整理——python的安装以及pycharm安装
一.python的安装 首先我们来谈一谈python的安装,python的官网地址:Welcome to Python.org编辑 进入官网后点击Downloads,然后选择自己对应的系统,比如 ...
- Spring Boot整合log4j实战(一):排除自带依赖、日志重定向、测试类验证
〇.参考资料 1.springboot整合log4j全过程详解 https://blog.csdn.net/m0_60845963/article/details/123307232 2.Spring ...
- Thrift RPC添加access log
前言: 当我们在部署web服务的时候,web容器通常都会记录来自客户端的访问日志.而当我们使用Thrift RPC服务的时候,Thrift服务则不会给我们自动记录客户端的访问日志. 通过这篇文章,你可 ...
- <三>function函数对象类型的应用示例
std::function是一组函数对象包装类的模板,实现了一个泛型的回调机制.function与函数指针比较相似,优点在于它允许用户在目标的实现上拥有更大的弹性,即目标既可以是普通函数,也可以是函数 ...
- Linux 系统用户文件缺失造成“bash-4.2$”错误的解决办法
一.问题出现的原因 造成这个现象的原因是因为用户文件夹下的bash_logout.bash_profile和bashrc这三个隐藏文件缺失 二.问题复现 现在删除这三个文件 此时问题出现了 三.问题解 ...
- 如何在SpringBoot中优雅地重试调用第三方API?
前言 作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端.但你不能保证所有的事情一直都很顺利.像有些第三方API,偶尔会出现超时.此时,我们要重试几次,这取决于你的 ...
- python循环结构之for循环
在python中,for循环是应用非常广的循环语句,遍历字典.遍历列表等等... # for语句结构 for 遍历 in 序列: 执行语句 遍历字典 lipsticks = {"Chanel ...
- 基于docker容器的MySQL主从设置及efcore读写分离
1.基于docker部署MySQL,设置主从 本操作基于已经拉取的镜像(docker pull mysql) 创建一主一从两个数据库容器 docker run -d -p 3307:3306 -e M ...