4302. 【NOIP2015模拟11.3】IOIOI卡片占卜

Description

K理事长很喜欢占卜,经常用各种各样的方式进行占卜。今天,他准备使用正面写着”I”,反面写着”O”的卡片为今年IOI的日本代表队占卜最终的成绩。
占卜的方法如下所示:
首先,选择5个正整数A,B,C,D,E。
将A+B+C+D+E张IOI卡片排成一行,最左侧的A张卡片正面朝上,接下来B张反面朝上,接下来C张卡片正面朝上,接下来D张反面朝上,最后E张正面朝上。如此排列的话,从左侧开始顺次为A张“I”,B张“O”,C张“I”,D张“O”,E张“I”。
在预先决定的N种操作中选出至少1种,然后按照任意顺序执行。(注:同种操作执行多次也是可以的。)这里,第i种操作(1<=i<=N)为【将从左数第Li张卡片到第Ri张卡片全部翻转】。翻转一张卡片需要1秒的时间,因此第i种操作耗时Ri-Li+1秒。
操作结束后,如果所有卡片都是正面朝上则占卜成功。K理事长不想翻多余的牌,因此在实际使用卡片占卜之前会先计算出是否存在占卜成功的可能性。进一步,如果占卜可能成功,他会计算出能使占卜成功所消耗的时间的最小值。
现在给出卡片的排列信息和预先决定的操作信息,请你写一个程序,计算出占卜能否成功,如果能成功,输出消耗时间的最小值。

Input

第一行5个空格分隔的整数A,B,C,D,E,表示占卜初始时,从最左端开始依次是A枚正面朝上,接下来B枚背面朝上,接下来C枚正面朝上,接下来D枚背面朝上,最后E枚正面朝上。
接下来一行一个正整数N,表示预先决定的操作种类数。
接下来N行,第i行(1<=i<=N)两个空格分隔的正整数Li,Ri,表示第i种操作为【将从左数第Li张卡片到第Ri张卡片全部翻转】。

Output

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

Sample Input

1 2 3 4 5
3
2 3
2 6
4 10

Sample Output

12
【HINT】
初始的卡片序列为IOOIIIOOOOIIIII。
执行第2种操作后得到IIIOOOOOOOIIIII,耗时5秒。
接下来执行第3中操作,得到IIIIIIIIIIIIIII,占卜成功,耗时7秒。
耗时12秒完成占卜,这是耗时的最小值,故输出12。

Data Constraint

对于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)

Solutioin

设原序列为SS
定义序列FF,FiFi=SiSi xor Si+1Si+1。

SS,FF序列内所含元素如下:

这里写图片描述

新的FF序列变成一堆0夹着4个1,我们的目标也就变成将FF序列全部变成0。
对于第ii个操作LiLi,RiRi也就变成了把FF[LiLi-1]和FF[RiRi]由0变成1,由1变成0。

转换完以后,我们可以怎样做呢?
我们把LiLi-1向RiRi连上一条权为RiRi-LiLi+1的双向边。
对于一条最短路径,路径上的每个点FF值的变化次数等于入度加上出度,这很明显。
又因为这是最短路径,所以除了起点和终点以外,每个点的入度和出度都为1,既FF的值没有变化。
然而起点的入度和出度的和为1,所以起点和终点的值会产生变化。

现在只需将这4个1分成两组,每组分别选一个1作为起点和另一个1作为终点,
做两次SPFA求最短路,并把两组的最小代价累加求最大值即可。

至于分组,只有三种情况。
<1>(1,2),(3,4)
<2>(1,3),(2,4)
<3>(1,4),(2,3)

注意ls[ i ]的下标是到N*5。

还有答案最大到10^10,因此inf要开到>10^10,可以1ll<<60。

一种是用x向y+1连边,这时注意对于点的下标最大值要+1,另一种是x-1向y连边,这时不用+1。当时在这里卡了很久。

总结:注意数组下标。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(register I i=a;i<=b;i++)
#define N 100004
using namespace std;
I n,x,y,z,now,l,r,a,b,c,d,e;
I t[N<<1],nx[N<<1],ls[N*5],bz[N*5],q[N*10],tot=0;
ll f[N*5],s[N<<1],inf=1ll<<60,ans=inf;
void add(I x,I y,ll z){t[++tot]=y,nx[tot]=ls[x],ls[x]=tot;s[tot]=z;}
ll work(I x,I y){
	F(i,0,n) f[i]=inf;
	l=f[q[r=1]=x]=0;
	while(l!=r){
		bz[now=q[++l]]=0;
		for(I k=ls[now];k;k=nx[k]){
			if(f[t[k]]>f[now]+s[k]){
				f[t[k]]=f[now]+s[k];
				if(!bz[t[k]]) bz[q[++r]=t[k]]=1;
			}
		}
	}
	return f[y];
}
I main(){
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&n);
	F(i,1,n){
		scanf("%d%d",&x,&y);
		add(x-1,y,y-x+1),add(y,x-1,y-x+1);
	}
	n=a+b+c+d+e,b+=a,c+=b,d+=c,e+=d;
	ans=min(ans,min(work(a,b)+work(c,d),min(work(a,c)+work(b,d),work(a,d)+work(b,c))));
	printf("%lld\n",ans==inf?-1:ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107694402