「JOISC 2015 Day 1」卡片占卜

「JOISC 2015 Day 1」卡片占卜

序列:\(1_10_21_30_41_5\)

要求令\(0_2,0_4\)取反为\(1_2,1_4\)

考虑将每次操作\([l,r ]\)转化为一条连接\(l\)\(r+1\)边(\(r+1\)点并未被反转)(双向边)。

假如要反转一个区间\([l,r]\),考虑\(l\)\(r+1\)的路径的效果:按照经过边对应的操作,必然只会取反\([l,r]\)区间,即仅有\([l,r ]\)区间的点被经过奇数次。

证明:

  1. 如果没有向左走,那么显然正确。

    1. 如果向左走边\(r_1->l_1\),那么\([l1,r1-1]\)反转了偶数次(无效),总体相当于反转\([l,l_1-1]\)区间。

因此反转一个指定区间所花费的最短时间可以通过一次\(dijkstra\)求出。

反转$1_2,1_4 $的方案共三种:

  1. 反转\(0_2,0_4\)
  2. 反转\(0_21_30_4,1_3\)
  3. 反转\(0_21_3,1_30_4\)
#include<bits/stdc++.h>
#define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
#define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
#define mem(a,b) memset(a,b,sizeof a )
#define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
using namespace std;
void in(int &r) {
	static char c;
	r=0;
	while(c=getchar(),!isdigit(c));
	do r=(r<<1)+(r<<3)+(c^48);
	while(c=getchar(),isdigit(c));
}
const int mn=500005;
int head[mn],ne[200005],to[200005],cnt1,cost[200005];
#define link(a,b,c) link_edge(a,b,c),link_edge(b,a,c)
#define link_edge(a,b,c) to[++cnt1]=b,ne[cnt1]=head[a],head[a]=cnt1,cost[cnt1]=c
#define travel(x) for(int q(head[x]);q;q=ne[q])
struct node{
	long long v;
	int id;
	bool operator <(const node &A)const{
		return v>A.v;
	}
};
priority_queue<node> qw;
const long long INF=1e18;
long long d[mn];
int n,td;
bool mark[mn];
long long dijkstra(int s,int t){
    rep(q,1,td+1)d[q]=INF,mark[q]=0;
	while(!qw.empty())qw.pop();
	d[s]=0;
	qw.push({d[s],s});
	while(!qw.empty()){
		int now=qw.top().id;
		qw.pop();
		if(mark[now])continue;
		mark[now]=1;
		travel(now)if(d[to[q]]>d[now]+cost[q]){
			d[to[q]]=d[now]+cost[q];
			qw.push({d[to[q]],to[q]});
		}
	}
	if(d[t]==INF)return -1;
	return d[t];
}
int main(){
	int a,b,c,d,e;
	in(a),in(b),in(c),in(d),in(e);
	b+=a,c+=b,d+=c,e+=d;
	td=e;
	int x,y;
	in(n);
	rep(q,1,n)in(x),in(y),link(x,y+1,abs(y-x)+1);
	
	long long ans=INF,v1,v2;
	
	v1=dijkstra(a+1,b+1),v2=dijkstra(c+1,d+1);
	if(v1!=-1&&v2!=-1)ans=min(ans,v1+v2);
	
	v1=dijkstra(a+1,d+1),v2=dijkstra(b+1,c+1);
	if(v1!=-1&&v2!=-1)ans=min(ans,v1+v2);
	
	v1=dijkstra(a+1,c+1),v2=dijkstra(b+1,d+1);
	if(v1!=-1&&v2!=-1)ans=min(ans,v1+v2);
	
	if(ans==INF)ans=-1;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2019-08-01 16:41  Eeis  阅读(268)  评论(0编辑  收藏  举报