AT1252 IOIOI カード占い

AT1252 IOIOI カード占い

记原数组为 0101 数组。

差分,转化为一堆 004411

每次区间翻转操作即翻转差分数组两点。

答案即翻转 4411 的最小操作数,转化为操作任意两点和操作另外两次两次操作。

以每个 11 点为起点跑最短路即可,一条路径对应翻转两点。

时间复杂度 O(nlogn)\mathcal O(n\log n)

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define ha putchar(' ')
#define he putchar('\n')

inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x * f;
}

inline void write(ll x)
{
	if(x < 0)
	{
		putchar('-');
		x = -x;
	}
	if(x > 9)
		write(x / 10);
	putchar(x % 10 + 48);
}

const int _ = 5e5 + 10;
const ll inf  = 0x3f3f3f3f3f3f3f3f;

int n, a[6];

bool vis[_];

ll dis[3][_], ans = inf;

vector<ll> d[_], w[_];

void dij(int s, ll *di)
{
	memset(vis, 0, sizeof vis);
	priority_queue<pair<ll, int>> q;
	q.push({0, s});
	di[s] = 0;
	while(!q.empty())
	{
		int u = q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = 0; i < d[u].size(); ++i)
		{
			int v = d[u][i];
			if(di[v] > di[u] + w[u][i])
			{
				di[v] = di[u] + w[u][i];
				if(!vis[v]) q.push({-di[v], v});
			}
		}
	}
}

signed main()
{
	memset(dis, inf, sizeof dis);
	for(int i = 1; i <= 5; ++i) a[i] = read() + a[i - 1];
	n = read();
	for(int i = 1, u, v; i <= n; ++i)
	{
		u = read(), v = read();
		d[u].push_back(v + 1), d[v + 1].push_back(u);
		w[u].push_back(v - u + 1), w[v + 1].push_back(v - u + 1);
	}
	dij(a[1] + 1, dis[0]), dij(a[2] + 1, dis[1]), dij(a[3] + 1, dis[2]);
	ans = min(ans, dis[0][a[2] + 1] + dis[2][a[4] + 1]);
	ans = min(ans, dis[0][a[3] + 1] + dis[1][a[4] + 1]);
	ans = min(ans, dis[0][a[4] + 1] + dis[1][a[3] + 1]);
	write(ans == inf ? -1 : ans), he;
	return 0;
}
posted @ 2022-08-21 19:31  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源