纪中暑假集训 2020.07.30【NOIP提高组】模拟 T3:【NOIP2015模拟11.3】IOIOI卡片占卜

【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)

反思&题解

比赛思路: 日常懵逼,遂干暴力,n大于50直接输出-1……您猜怎么着?47分!Ohhhhhh!良心啊!
正解思路: 将每相邻两个数异或一下,就变成了一个只有4个1的序列,根据其性质来说就是要把这4个1全部变成0,于是很显然想到了最短路,将每个可以变化的区间 [ l , r ] [l,r] [l,r]连一条 l − 1 l-1 l1 r r r点边,边权为 r − l + 1 r-l+1 rl+1,so把每两个1的点两两组合统计答案就行了
反思: 对于图论的理解还是要加深

CODE

#include
using namespace std;
struct arr
{
	long long to,next,w;
}edge[500005];
queue<int>q;
const long long inf=1e17;
long long a,b,c,d,e,head[500005],n,cnt,ans,sum,dist[500005];
bool bz[500005];
void add(long long u,long long v,long long len)
{
	edge[++cnt].to=v;
	edge[cnt].w=len;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
void spfa(long long s)
{
	long long i;
	for (i=0;i<=sum;i++)
		dist[i]=inf;
	memset(bz,false,sizeof(bz));
	dist[s]=0;
	q.push(s);
	while (!q.empty())
	{
		long long u=q.front();
		q.pop();
		for (i=head[u];i;i=edge[i].next)
		{
			long long v=edge[i].to;
			if (dist[u]+edge[i].w<dist[v])
			{
				dist[v]=dist[u]+edge[i].w;
				if (!bz[v])
				{
					q.push(v);
					bz[v]=true;
				}
			}
		}
		bz[u]=false;
	}
}
int main()
{
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e);
	sum=a+b+c+d+e;
	long long t1=a,t2=a+b,t3=a+b+c,t4=a+b+c+d;
	scanf("%lld",&n);
	long long i;
	for (i=1;i<=n;i++)
	{
		long long l,r;
		scanf("%lld%lld",&l,&r);
		add(l-1,r,r-l+1);
		add(r,l-1,r-l+1);
	}
	ans=inf;
	spfa(t1);
	long long tot1=dist[t2];
	spfa(t3);
	long long tot2=dist[t4];
	ans=min(ans,tot1+tot2);
	spfa(t1);
	tot1=dist[t3];
	spfa(t2);
	tot2=dist[t4];
	ans=min(ans,tot1+tot2);
	spfa(t1);
	tot1=dist[t4];
	spfa(t2);
	tot2=dist[t3];
	ans=min(ans,tot1+tot2);
	if (ans!=inf) printf("%lld\n",ans);
	else printf("-1\n");
	return 0;
}

你可能感兴趣的:(题解,反思)