[20200730NOIP提高组模拟T3]IOIOI占卜

题目大意:

  今有五变量,ABCDE者也.构造一字符序列A个'I',B个'O',C个'I',D个'O',E个'I'相接也.现有如下操作:给定变量\(l,r\),可将区间\([l,r]\)内的'I'反转为'O','O'反转为'I',代价为\(r-l+1\),请你求出将该序列变为全'I'序列所需的最小代价,若无法变为全'I',则输出\(-1\).

solution:

此题非常神奇,可转化为最短路,下面给出证明.为将此题转化为最短路,我们引进一个辅助的差分序列,\(x\)处的值表示\(x\)\(x-1\)处的值相异或的结果,于是我们每次进行\([l,r]\)操作时,改变的值只有\(l\)\(r+1\)处的值,所以我们可以看作在添加一条带权边\(<l,r+1,r-l+1>\),然后分情况讨论,一一枚举以\(A+1,A+B+1,A+B+C+1,A+B+C+D+1,A+B+C+D+E+1\)为起点终点符合题目要求的最短路即可.

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod 1000000007
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll A,B,C,D,E,n; 
ll to[1000000],head[1000000],next[1000000],tot,w[1000000];
inline void add(ll x,ll y,ll z){to[++tot]=y;next[tot]=head[x];head[x]=tot;w[tot]=z;}
ll ans,dist;
ll dis[1000000];
bool vis[1000000];
queue<ll>q;

inline ll spfa(ll S,ll T){
	while(q.size())q.pop();
	memset(vis,false,sizeof vis);
	memset(dis,0x3f,sizeof dis);
	dis[S]=0;q.push(S);
	while(q.size()){
		ll x=q.front();q.pop();vis[x]=false;
		for(R ll i=head[x],ver;i;i=next[i]){
			ver=to[i];
			if(dis[ver]>dis[x]+w[i]){
				dis[ver]=dis[x]+w[i];
				if(!vis[ver]){
					vis[ver]=true;
					q.push(ver);
				}
			}
		}
	}
	return dis[T];
}

int main(){
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	A=read()+1;
	B=read()+A;
	C=read()+B;
	D=read()+C;
	E=read()+D;
	n=read();
	for(R ll i=1,l,r;i<=n;i++){
		l=read();r=read();
		add(l,r+1,r-l+1);add(r+1,l,r-l+1);
	}
	dist=spfa(A,B);
	ans=dis[0];
	if(dist<dis[0]) ans=min(ans,dist+spfa(C,D));
	dist=spfa(A,C); 
	if(dist<dis[0]) ans=min(ans,dist+spfa(B,D));
	dist=spfa(A,D);
	if(dist<dis[0]) ans=min(ans,dist+spfa(B,C));
	writeln(ans>=dis[0]?-1:ans);
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
posted @ 2020-07-30 15:15  月落乌啼算钱  阅读(129)  评论(1编辑  收藏  举报