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

Solution

乍一看好像很难得样子,实际上只是一个简单的最短路。
I为1,O为0把。每一个数与后面那个数异或,就会得到一堆0中间加在4个1。
将l到r区间翻转就是把新的串中的l-1于r取反。(随便用样例试一下就知道了)
目标就是把这个新串变成全部是0。
那么每次的操作就把l-1到r连边,边权为r-l+1。
那么四个1两两配对找最短路即可。(1-2,3-4 1-3,2-4 1-4,2-3)只有三种。

code

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#define N 501000
#define ll long long
using namespace std;
int n,m,tot=0,d[N*10],to[N*2];
ll last[N*2],next[N*2],data[N*2],f[N];
bool bz[N];
void putin(int x,int y,ll z)
{
    next[++tot]=last[x];last[x]=tot;to[tot]=y;data[tot]=z;
}
ll spfa(int s,int t)
{
    memset(f,60,sizeof(f));memset(bz,0,sizeof(bz));
    int i=0,j=1;f[s]=0;d[1]=s;bz[s]=1;
    for(;i<j;)
    {
        int x=d[++i];
        for(int k=last[x];k;k=next[k])
        {
            int y=to[k];
            if (f[x]+data[k]<f[y])
            {
                f[y]=f[x]+data[k];
                if (!bz[y]) {bz[y]=1;d[++j]=y;}
            }
        }
        bz[x]=0;
    }
    return f[t];
}
int main()
{
    freopen("card.in","r",stdin);freopen("card.out","w",stdout);
    int jy1,jy2,jy3,jy4,jy5;
    scanf("%d%d%d%d%d",&jy1,&jy2,&jy3,&jy4,&jy5);
    n=jy1+jy2+jy3+jy4+jy5;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        putin(x-1,y,y-x+1);putin(y,x-1,y-x+1);
    }
    ll ans=250000000000;jy2+=jy1;jy3+=jy2;jy4+=jy3;jy5+=jy4;
    ans=min(ans,spfa(jy1,jy2)+spfa(jy3,jy4));
    ans=min(ans,spfa(jy1,jy3)+spfa(jy2,jy4));
    ans=min(ans,spfa(jy1,jy4)+spfa(jy2,jy3));
    ans=(ans>=250000000000)?-1:ans;
    printf("%lld",ans);
    fclose(stdin);fclose(stdout);
}

你可能感兴趣的:(最短路)