1. 程式人生 > >【JOI Camp 2015】IOIO卡片占蔔——最短路

【JOI Camp 2015】IOIO卡片占蔔——最短路

spa 意義 tin 技術分享 none != click isdigit ooo

題目

【題目描述】
K 理事長是占蔔好手,他精通各種形式的占蔔。今天,他要用正面寫著 `I` ,背面寫著 `O` 的卡片占蔔一下日本 IOI 國家隊的選手選擇情況。
占蔔的方法如下:
1. 首先,選取五個正整數 $A,B,C,D,E$;
2. 然後,拿出 $A+B+C+D+E$ 張卡片擺成一排,從左至右擺成 $A$ 張正面,$B$ 張反面,$C$ 張正面,$D$ 張反面,$E$ 張正面的形式。也就是說,從左到右依次擺 $A$ 張 `I`,$B$ 張 `O`,$C$ 張 `I`,$D$ 張 `O`,$E$ 張 `I`;
3. 再從預先確定的 $N$ 種操作中選擇 $1$ 種以上,然後按照自己喜歡的順序進行操作,同樣的操作可以進行 $1$ 次及以上。第 $i$ 種操作是「把從左到右第 $L_i$ 張卡片到第 $R_i$ 張卡片(包括兩端)翻過來」,因為需要用手操作,所以翻 $1$ 張牌需要花費 $1$ 秒,完成一次操作需要花費 $R_i-L_i+1$ 秒;

4. 操作後,如果所有牌都是正面朝上的,占蔔就結束了。
因為這種占蔔比較費時,所以 K 理事長在占蔔之前想知道占蔔能否結束,如果能結束,他想知道占蔔的最小耗時。
【輸入格式】
第一行,五個正整數 $A,B,C,D,E$,意義如題目描述;
第二行,一個正整數 $N$,意義如題目描述;
接下來 $N$ 行描述操作,一行兩個正整數 $L_i,R_i$,意義如題目描述。
【輸出格式】
輸出一行,如果占蔔能夠結束,則輸出一個正整數,表示占蔔的最小耗時;如不能,輸出 $-1$。
【樣例輸入一】
1 2 3 4 5
3
2 3
2 6
4 10
【樣例輸出一】
12
【樣例解釋一】
最初的卡片序列為 `IOOIIIOOOOIIIII`;
先進行第二個操作,卡片序列變為 `IIIOOOOOOOIIIII`,花費 $5$ 秒;
再進行第三個操作,卡片序列變為 `IIIIIIIIIIII`,這個操作花費 $7$ 秒,一共花費 $12$ 秒。
可以證明,$12$ 秒為占蔔的最小耗時,因此輸出 $12$。
【樣例輸入二】
1 1 1 1 1
1
1 1
【樣例輸出二】
-1

題解

考慮覆蓋,從 $ i $ 覆蓋到 $ j $ 相當於通過那些翻轉,從 $ i $ 走到 $ j $(畫圖手動感知)

然後就變成了最短路,分別枚舉起點和終點就可以了

(本題卡 int)

代碼

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define _(d) while(d(isdigit(ch=getchar())))
 4
using namespace std; 5 int R(){ 6 int x;bool f=1;char ch;_(!)if(ch==-)f=0;x=ch^48; 7 _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;} 8 const int N=5e5+5; 9 int n,a[6],head[N],cnt;LL dis[N],ans=2e18; 10 struct edge{int to,nex,w;}e[N<<1]; 11 struct node{ 12 int x;LL w; 13 bool friend operator <(node a,node b){return a.w>b.w;} 14 };priority_queue<node>q; 15 void add(int s,int t,int w){e[++cnt]=(edge){t,head[s],w},head[s]=cnt;} 16 void dij(int s){ 17 for(int i=0;i<=a[5];i++)dis[i]=2e18; 18 dis[s]=0; 19 q.push((node){s,0}); 20 while(!q.empty()){ 21 node now=q.top();q.pop(); 22 if(now.w!=dis[now.x])continue; 23 for(int v,k=head[now.x];k;k=e[k].nex) 24 if(dis[v=e[k].to]>dis[now.x]+e[k].w) 25 dis[v]=dis[now.x]+e[k].w,q.push((node){v,dis[v]}); 26 } 27 return; 28 } 29 int main(){ 30 for(int i=1;i<=5;i++)a[i]=a[i-1]+R(); 31 n=R(); 32 for(int i=1,u,v;i<=n;i++) 33 u=R()-1,v=R(),add(u,v,v-u),add(v,u,v-u); 34 dij(a[1]); 35 LL s1=dis[a[2]],s2=dis[a[3]],s3=dis[a[4]]; 36 dij(a[2]); 37 ans=min(min(ans,s2+dis[a[4]]),s3+dis[a[3]]); 38 dij(a[3]); 39 ans=min(ans,s1+dis[a[4]]); 40 printf("%lld\n",ans==2e18?-1:ans); 41 return 0; 42 }
View Code

【JOI Camp 2015】IOIO卡片占蔔——最短路