Description
就像你看到的題目一樣,現在有A個I,接着B個O,再接着C個I,再接着D個O,再接着E個I,排成一排。你現在有N種操作,第i種操作吧從第li個字元到第ri個字元這個區間内的字元,I變成O,O變成I,時間為ri-li+1。求把所有字元都變成I的最小時間。若無解輸出-1。
A,B,C,D,E,N<=10^5
Solution
神奇的一道題。
先%%出題人,這種思路誰想得到嘛~
Japanese…
首先,我們建立一個新的序列b,bi=ai^ai+1
這樣子,b中有了一堆0,中間有4個1。
那麼一次操作相當于什麼呢?
相當于把bl-1和br取反!(自己想想為什麼)
那麼,我們可以從l-1向r連一條長度為r-l+1的邊。
而我們的任務就變成了把b序列變成0.(雖然原序列全為0,b序列也全為0,但這是不可能的,自己想想為什麼)
那麼對于兩個1,把它們同時變為0的最小花費為,這兩個1中間的最短路!(自己想想為什麼)
那麼,我們隻需要打一個spfa/迪傑斯特拉就好了。
不過經過棟爺的測試,迪傑斯特拉好像過不了。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 500005
#define ll long long
using namespace std;
int n,tot,g[][]={,,,,,,,,,,,};
int t[N*],next[N*],last[N],a[],d[N*];
ll dis[N],v[N*],ans,l,r;
bool bz[N];
void add(int x,int y,ll z){
t[++tot]=y;v[tot]=z;next[tot]=last[x];last[x]=tot;
}
ll spfa(int S,int T) {
memset(dis,,sizeof(dis));
ll mx=dis[S];dis[S]=;
memset(bz,,sizeof(bz));bz[S]=;
int i=,j=;d[]=S;
while (i<j) {
rep(k,d[++i]) if (dis[t[k]]>dis[d[i]]+v[k]) {
dis[t[k]]=dis[d[i]]+v[k];
if (!bz[t[k]]) bz[t[k]]=,d[++j]=t[k];
}
bz[d[i]]=;
}
if (dis[T]==mx) return -;else return dis[T];
}
int main() {
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
fo(i,,) scanf("%d",&a[i]),a[i]+=a[i-];
scanf("%d",&n);ans=;
fo(i,,n) scanf("%lld%lld",&l,&r),add(l-,r,r-l+),add(r,l-,r-l+);
fo(i,,) {
ll x=spfa(a[g[i][]],a[g[i][]]),y=spfa(a[g[i][]],a[g[i][]]);
if (x==-||y==-) continue;
ans=min(ans,x+y);
}
if (ans==) printf("-1");else printf("%lld",ans);
}