您的位置:首页 > 其它

【JOI Camp 2015】IOIO卡片占卜

2016-08-07 16:48 281 查看

Description

K理事长很喜欢占卜,经常用各种各样的方式进行占卜。今天,他准备使用正面写着”I”,反面写着”O”的卡片为今年IOI的日本代表队占卜最终的成绩。

占卜的方法如下所示:

1、首先,选择5个正整数A,B,C,D,E。

2、将A+B+C+D+E张IOI卡片排成一行,最左侧的A张卡片正面朝上,接下来B张反面朝上,接下来C张卡片正面朝上,接下来D张反面朝上,最后E张正面朝上。如此排列的话,从左侧开始顺次为A张“I”,B张“O”,C张“I”,D张“O”,E张“I”。

3、在预先决定的N种操作中选出至少1种,然后按照任意顺序执行。(注:同种操作执行多次也是可以的。)这里,第i种操作(1<=i<=N)为【将从左数第Li张卡片到第Ri张卡片全部翻转】。翻转一张卡片需要1秒的时间,因此第i种操作耗时Ri-Li+1秒。

4、操作结束后,如果所有卡片都是正面朝上则占卜成功。

K理事长不想翻多余的牌,因此在实际使用卡片占卜之前会先计算出是否存在占卜成功的可能性。进一步,如果占卜可能成功,他会计算出能使占卜成功所消耗的时间的最小值。

现在给出卡片的排列信息和预先决定的操作信息,请你写一个程序,计算出占卜能否成功,如果能成功,输出消耗时间的最小值。

Input

第一行5个空格分隔的整数A,B,C,D,E,表示占卜初始时,从最左端开始依次是A枚正面朝上,接下来B枚背面朝上,接下来C枚正面朝上,接下来D枚背面朝上,最后E枚正面朝上。

接下来一行一个正整数N,表示预先决定的操作种类数。

接下来N行,第i行(1<=i<=N)两个空格分隔的正整数Li,Ri,表示第i种操作为【将从左数第Li张卡片到第Ri张卡片全部翻转】。n,m≤1000000。

Output

如果占卜能够成功,输出消耗时间的最小值,否则输出-1。

SampleInput

1 2 3 4 5

3

2 3

2 6

4 10

SampleOutput

12

Hint

【样例解释】

初始的卡片序列为IOOIIIOOOOIIIII。

执行第2种操作后得到IIIOOOOOOOIIIII,耗时5秒。

接下来执行第3中操作,得到IIIIIIIIIIIIIII,占卜成功,耗时7秒。

耗时12秒完成占卜,这是耗时的最小值,故输出12。

【数据范围与约定】

对于15%的数据,N<=10

对于另外50%的数据,1<=A,B,C,D,E<=50

对于100%的数据:1<=A,B,C,D,E,N<=10^5,1<=Li<=Ri<=A+B+C+D+E (1<=i<=N)

Solution

对于第i种操作的Li和Ri,如果在他们之间画上一条线:



不难发现如果要把一段区间完全翻转,那么这一区间的每一部分都应该要有奇数个线段覆盖。

奇数个线段的话,如果把每个端点当成G中的一个点,每条线段当做一条双向边,那么一定有一条路径从被完全翻转的区间的起点通向它的终点,想要让操作次数最少,这不由得让我们想到最短路。

在每个I和O的转换点处跑Spfa即可,总共有三种方式:



答案即为最小者。

Code

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
typedef long long ll;

const int MAXN=5e5+10;
const ll INF=1e18+10;

int A,B,C,D,E,n;
ll dist=INF,ans=INF;

ll dis[MAXN];
bool inq[MAXN];
int head[MAXN],cnt;
struct edge{int to,nxt; ll c;}e[MAXN<<1];

int Getint(){
char ch; while(!isdigit(ch=getchar())); int v=ch-48;
while(isdigit(ch=getchar())) v=(v<<3)+(v<<1)+ch-48; return v;
}

void Insert(int u,int v,ll cost){
e[++cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt; e[cnt].c=cost;
e[++cnt].to=u; e[cnt].nxt=head[v]; head[v]=cnt; e[cnt].c=cost;
}

queue<int> Q;
ll Spfa(int s,int t){
for(int i=1;i<=E+1;i++) dis[i]=INF; dis[s]=0;
Q.push(s); inq[s]=true;
while(!Q.empty()){
int now=Q.front(); Q.pop();
for(int i=head[now];i;i=e[i].nxt){
if(dis[e[i].to]>dis[now]+e[i].c){
dis[e[i].to]=dis[now]+e[i].c;
if(!inq[e[i].to]){
Q.push(e[i].to);
inq[e[i].to]=true;
}
}
}
inq[now]=false;
}
return dis[t];
}

int main(){
A=Getint();
B=A+Getint(); C=B+Getint();
D=C+Getint(); E=D+Getint();
n=Getint();
int s,t;
for(int i=1;i<=n;i++){
s=Getint(); t=Getint();
Insert(s,t+1,(ll)t-s+1);
}
dist=Spfa(A+1,B+1);
if(dist<INF) ans=min(ans,dist+Spfa(C+1,D+1));
dist=Spfa(A+1,C+1);
if(dist<INF) ans=min(ans,dist+Spfa(B+1,D+1));
dist=Spfa(A+1,D+1);
if(dist<INF) ans=min(ans,dist+Spfa(B+1,C+1));
printf("%lld\n",ans>=INF?-1:ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  题解 图论 最短路 Spfa