首页 > 其他分享 >QOJ 5175 翻修道路

QOJ 5175 翻修道路

时间:2023-09-25 11:56:00浏览次数:39  
标签:typedef 5175 int ll long 翻修 maxn QOJ define

QOJ 传送门

考虑 \(1\) 到其他关键城市的最短路的并是一棵以 \(1\) 为根的外向树,考虑在外向树上从叶子往根 dp。

设 \(f_{u, i, S}\) 为当前在点 \(u\),已经翻修了 \(i\) 条道路,当前已经经过的关键点集合为 \(S\),最短路最大值的最小值。

转移有两种情况,一种是在外向树上往父亲的边走,有 \(f_{v, i, S} \gets f_{u, i, S} + a, f_{v, i + 1, S} \gets f_{u, i, S} + b\)。

一种是在一个点把两棵子树合并,有 \(f_{u, i + j, S \cup T} \gets \max(f_{u, i, S}, f_{u, j, T})\)。朴素转移时间复杂度不能接受。因为 \(f_{u, i, S}\) 按 \(i\) 是单调不降的,考虑只用找到第一个 \(f_{u, j, T} \le f_{u, i, S}\) 即可转移。然后将 \(f_{u, i, S}\) 更新为 \(i\) 的前缀最小值即可。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 110;
const int maxm = 260;

struct edg {
	ll v, a, b;
	edg(ll x = 0, ll y = 0, ll z = 0) : v(x), a(y), b(z) {}
};

ll n, m, K, id[maxn], f[maxn][maxn][maxm];
bool vis[maxn][maxn];
vector<edg> G[maxn];

struct node {
	ll u, i, d;
	node(ll a = 0, ll b = 0, ll c = 0) : u(a), i(b), d(c) {}
};

inline bool operator < (const node &a, const node &b) {
	return a.d > b.d;
}

void solve() {
	scanf("%lld%lld%lld", &n, &m, &K);
	mems(f, 0x3f);
	for (int i = 0, x; i < K; ++i) {
		scanf("%d", &x);
		f[x][0][1 << i] = 0;
	}
	for (int i = 1, u, v, a, b; i <= m; ++i) {
		scanf("%d%d%d%d", &u, &v, &a, &b);
		G[v].pb(u, a, b);
	}
	for (int S = 1; S < (1 << K); ++S) {
		priority_queue<node> pq;
		for (int u = 1; u <= n; ++u) {
			for (int T = (S - 1) & S; T; T = (T - 1) & S) {
				int U = S ^ T;
				for (int i = 0, j = 0; i <= m; ++i) {
					while (j < m && f[u][j][T] > f[u][i][U]) {
						++j;
					}
					if (i + j <= m) {
						f[u][i + j][S] = min(f[u][i + j][S], max(f[u][i][U], f[u][j][T]));
					} else {
						break;
					}
				}
			}
			for (int i = 1; i <= m; ++i) {
				f[u][i][S] = min(f[u][i][S], f[u][i - 1][S]);
			}
			for (int i = 0; i <= m; ++i) {
				if (f[u][i][S] < 1e9) {
					pq.emplace(u, i, f[u][i][S]);
				}
			}
		}
		mems(vis, 0);
		while (pq.size()) {
			int u = pq.top().u, i = pq.top().i;
			pq.pop();
			if (vis[u][i]) {
				continue;
			}
			vis[u][i] = 1;
			for (edg e : G[u]) {
				ll v = e.v, d1 = e.a, d2 = e.b;
				if (f[v][i][S] > f[u][i][S] + d1) {
					f[v][i][S] = f[u][i][S] + d1;
					if (!vis[v][i]) {
						pq.emplace(v, i, f[v][i][S]);
					}
				}
				if (i < m && f[v][i + 1][S] > f[u][i][S] + d2) {
					f[v][i + 1][S] = f[u][i][S] + d2;
					if (!vis[v][i + 1]) {
						pq.emplace(v, i + 1, f[v][i + 1][S]);
					}
				}
			}
		}
	}
	for (int i = 0; i <= m; ++i) {
		printf("%lld ", f[1][i][(1 << K) - 1]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,5175,int,ll,long,翻修,maxn,QOJ,define
From: https://www.cnblogs.com/zltzlt-blog/p/17727640.html

相关文章

  • QOJ 5019 整数
    QOJ传送门考虑从低位向高位dp,设\(f_{i,S}\)为考虑到从低到高第\(i\)位,当前每个数超出上界的情况为\(S\)。转移可以枚举这一位填的数:若\(a_j=0,r_j=1\),那么这一位一定不会超出上界;若\(a_j=1,r_j=0\),那么这一位一定会超出上界。否则情况和之前相同。容......
  • QOJ 5089
    你细品巨大多太阳的题解,虽然看不懂,但是发现挺有道理的。容易发现,一个无向图是可环覆盖图,当且仅当所有点的度数为偶数。所以将一条边\((u,v)\)看作集合\(\{u,v\}\),相当于求选出\(i\in[0,m]\)个集合\(\{u_i,v_i\}\),其对称差为\(\varnothing\)的方案数。考虑集合幂级数,由......
  • QOJ61 Cut Cut Cut! 题解
    题面。题解假设\(1\)号点有\(d\)条出边,给\(d\)条出边赋\(d\)个独立的单位向量,接下来,每个出边记作入边的随机线性组合,那么对于第\(i\)个点,答案就是入边生成的线性空间的秩。正确性证明:对于每个点考虑,假设现在考虑\(i\)号点,将其入边集合记作\(E1_{i}\),出边集合记......
  • QOJ # 7106. Infinite Parenthesis Sequence
    题面传送门为什么全场切我不会?为什么全场切我不会?为什么全场切我不会?首先因为题目中要求左括号个数,我们就来关注一下左括号。对于一个左括号,假设它右边是右括号,那么这个左括号就会往右走,否则不会往右走。随便选个左括号开始标号,往左为负,往右为正,设\(p(k,i)\)表示第\(i\)个......
  • QOJ # 5573. Holiday Regifting
    题面传送门感觉有点奇妙。首先一个基础的想法就是一个一个往下推,维护每个数往下推的次数,统计当前数在前面的所有数一次归零后会加几次,然后计算这个数需要前面几轮归零,这样将这些系数乘起来就是需要归零的次数了。但是现在有一个问题就是前面每个数往下推的次数可能很大,这东西存......
  • P5175 数列
    Updated2023.07.05修正了一处笔误,在此感谢@DWT8125题解首先先推一下柿子,因为数据范围很大,所以考虑矩阵加速递推。根据题意给的递推式,可得:\[\begin{aligned}a_i^2 &=(x\timesa_{i-1}+y\timesa_{i-2})^2\\ &=x^2\timesa_{i-1}^2+y^2\timesa_{i-2}^2+2xy\timesa_{......
  • QOJ # 6355. 5
    题面传送门设题目中给出的\(1\)的个数占总数的\(\frac{m}{k}\)。考虑一个最朴素的\(O(n^3)\)dp:设\(f_{i,j}\)表示选择了\(i\)个,总和为\(j\)是否存在。当我们用\(j-i\)代替\(j\)的时候显然答案不会被改变,而好处在于可以把\(1\)拉出来单独考虑。当我们不考虑\(1......
  • QOJ # 6354. 4
    题面传送门我是傻逼。首先你看这东西长得一脸四元环计数那类东西,于是先给边定向,这样子的话就形成了一张图,每个点只有\(O(\sqrtm)\)条出边。现在我们枚举一个三元环,要计算三个点都指向的点的个数。直接做有\(O(m\sqrtm)\)个三元环,每个三元环需要\(O(\frac{m}{\omega})\)......
  • FS5175兼容PD 和 QC 快充充电器输入双节锂电池 2A 充电 IC 方案
    FS5175兼容PD 和 QC 快充充电器输入双节锂电池 2A 充电 IC 方案1.2 应用:便捷充电设备等1.3电池组:7.4V锂电池组,两串多并,充满8.4V1.4 输入电压:5V-12V (充电亮灯,充满转灯,不接电池是闪灯)1.5 Max充电电流:1A1.6芯片功能简介:1,锂电池充电电路:FS4067FS4062AFS4067锂电......
  • FS5175兼容PD 和 QC 快充充电器输入三节锂电池 2A 充电 IC 方案
    FS5175兼容PD 和 QC 快充充电器输入三节锂电池 2A 充电 IC 方案1.2   应用:便捷充电设备等1.3 电池组:7.4V锂电池组,两串多并,充满8.4V1.4   输入电压:5V-12V   (充电亮灯,充满转灯,不接电池是闪灯)1.5   Max充电电流:1A1.6芯片功能简介:1, 锂电池充电电路:FS4067 FS4062A......