[AT1252] IOIOI カード占い

前言

考场上想出( ext{Dijkstra})的是魔鬼吧

毫无防备地流下了属于真正弱者的泪水.jpg

题目

洛谷

讲解

所有的 I 被我换成了(1),而 O 换成了(0)

暴力

从考场思路开始吧

首先有显而易见的结论:

1.选择的操作顺序不影响答案

2.每个操作重复做没有意义

好了,这就是我们暴力的基础

(2^n)枚举操作,判断是否成立,取时间最小值即可

我是用(bitset)实现的,这里代码就不给出了

正解

差分 & 最短路

区间修改?好难啊! -> 差分!单点修改

如果当前点和前一个点不一样,取(1),反之取(0)

如样例可这样变化:

(100111000011111)

(010100100010000)

现在我们只需将所有的(1)改为(0)即可

上面所对应的(1)的位置为:

A+1 , A+B+1 , A+B+C+1 , A+B+C+D+1

由于差分后变为单点修改,那么我们的修改操作也变为了两个点的单点修改

(u,v)的区间修改变为了(u,v+1)的单点修改

记上面对应的(1)的位置为(a,b,c,d)

我们就有三个修改方案:(ab & cd , ac & bd , ad & bc)

而修改两个点的最小代价就可以用最短路算法( ext{dijkstra})求得

由于起点只有(a,b,c)三个点,所以我们需要跑三次( ext{dijkstra})

最后答案取最小值就好了

坑点

  1. 注意开( ext{long long})

  2. 空间要开(5e5)而非(1e5)

  3. 答案输出要换行! (( ext{AT})老题特性)

代码

//12252024832524
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; 

typedef long long LL;
const int MAXN = 500005;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n,init[6];
LL dis[3][MAXN],ans = INF;
struct node
{
	int x;
	LL d;
	node(){}
	node(int x1,LL d1){
		x = x1;
		d = d1;
	}
	bool operator < (const node &px) const{
		return d >= px.d;
	}
};

int Read()
{
	int x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put1(LL x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
void Put(LL x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
	if(c >= 0) putchar(c);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}

int head[MAXN],tot;
struct edge
{
	int v,val,nxt;
}e[MAXN << 1];
void Add_Edge(int x,int y,int z)
{
	e[++tot].v = y;
	e[tot].val = z;
	e[tot].nxt = head[x];
	head[x] = tot;
}
void Add_Double_Edge(int x,int y,int z)
{
	Add_Edge(x,y,z);
	Add_Edge(y,x,z);
}
void dij(int s,LL *DIS)
{
	priority_queue<node> q;
	q.push(node(s,0));
	DIS[s] = 0;
	while(!q.empty())
	{
		node t = q.top();
		q.pop();
		if(t.d > DIS[t.x]) continue;
		for(int i = head[t.x]; i ;i = e[i].nxt)
		{
			if(DIS[e[i].v] > DIS[t.x] + e[i].val) 
			{
				DIS[e[i].v] = DIS[t.x] + e[i].val;
				q.push(node(e[i].v,DIS[e[i].v]));
			}
		}
	}
}

int main()
{
//	freopen("cards.in","r",stdin);
//	freopen("cards.out","w",stdout);
	memset(dis,INF,sizeof(dis));
	for(int i = 1;i <= 5;++ i) init[i] = Read() + init[i-1];
	n = Read();
	for(int i = 1,u,v;i <= n;++ i) u = Read(),v = Read(),Add_Double_Edge(u,v+1,v-u+1);
	dij(init[1]+1,dis[0]);//A
	dij(init[2]+1,dis[1]);//B
	dij(init[3]+1,dis[2]);//C
	ans = Min(ans,dis[0][init[2]+1] + dis[2][init[4]+1]);//AB & CD
	ans = Min(ans,dis[0][init[3]+1] + dis[1][init[4]+1]);//AC & BD
	ans = Min(ans,dis[0][init[4]+1] + dis[1][init[3]+1]);//AD & BC
	if(ans == INF) Put(-1,'
');
	else Put(ans,'
');
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13392235.html