洛谷 P7078 - [CSP-S2020] 貪吃蛇(貪心)
題意:
- 有 \(n\) 條蛇,每條蛇有個實力 \(a_i\)
- 我們稱編號為 \(x\) 的蛇比編號為 \(y\) 的蛇強,當且僅當 \(a_x>a_y\) 或 \(a_x=a_y\) 且 \(x>y\)。
- 每次實力最強的蛇可以選擇吃掉實力最弱的蛇或者不吃,如果實力最強的蛇選擇吃,那麼它的實力會減去實力最弱的蛇的實力,實力最弱的蛇將消失。
- 假設每條蛇都會選擇最優策略(在保證自己不被吃的條件下吃掉儘可能多的別的蛇),問最後會剩下多少條蛇。
- \(\sum n\le 10^7\)
薅洛谷題解 ing
首先我們來挖掘一些性質。可以發現,如果一條蛇吃完最弱的蛇之後不是最弱的蛇,那麼它一定會選擇吃。因為如果最強的蛇吃完最弱的蛇之後還是最強的蛇,那它不吃白不吃。否則,下一步最強的蛇的實力肯定是弱於原來最強的蛇的實力的,並且由於這條蛇吃完之後不是最弱的蛇,最弱的蛇的實力也強於原來最弱的蛇的實力,也就是說,下一步最強的蛇吃完最弱的蛇之後,肯定比當前最強的蛇吃完最弱的蛇之後的實力更菜,也就是說,如果下一步最強的蛇死了,那它死的時間肯定比當前這條蛇死的時間早,而下一步最強的蛇肯定會選擇保住自己,因此下一步最強的蛇一定不會死,故就算這一步最強的蛇吃了最弱的蛇,它也不會死,因此它肯定會選擇吃。
那麼如果一條蛇吃了最弱的蛇之後變成了最弱的蛇之後怎麼辦呢?顯然,如果一條蛇吃了最弱的蛇之後變成了最弱的蛇,而下一步最強的蛇吃了最弱的蛇之後不是最弱的蛇,或者下一步只剩兩條蛇,那它肯定不會吃,因為如果它吃了最弱的蛇,那麼下一步最強蛇可以安心吃掉最弱的蛇,它也就掛掉了。
我們再往前回溯一格,如果一條蛇吃了最弱的蛇後,下一步最強的蛇滿足之前所述的狀態,那麼這條蛇會選擇吃掉最弱的蛇,因為下一步最強蛇不敢吃最弱的蛇,否則它就會死。因此這一步最強的蛇可以放心大膽地吃,而下一步的蛇又不敢吃,因此這種情況總蛇數會少一。
如果再往前回溯一格那也可以得到類似的結論,如果最強蛇吃完最弱蛇之後回到了上一步所說的狀態,那它又不敢吃了,因為吃了之後下一步最強蛇可以安心吃最弱蛇。
我們可以發現,出現最強蛇吃了最弱蛇的情況之後,答案會不會減少一,取決於當前局面到最強蛇能夠安心吃掉最弱蛇經過的輪數的奇偶性,如果不算“第一次出現最強蛇吃了最弱蛇變成最弱蛇”這一輪,算上“最強蛇能夠安心吃掉最弱蛇”這一輪之後,輪數是偶數,那麼答案會減少一。因此我們考慮將整個過程分為兩個部分:
- 第一部分:最強蛇吃完最弱蛇之後都不是最弱蛇,放心大膽吃,答案減一
- 第二部分:出現某個最強蛇吃完最弱蛇之後是最弱蛇:重複上面的過程直到出現一條最強蛇可以放心大膽地吃掉最弱蛇,根據第二部分持續的輪數判斷答案是否減一。
直接 set
維護大概可以拿到 70 分的好成績。考慮優化。我們建立兩個 deque
,分別稱作 \(q_1,q_2\)
- 第一部分:
- 每次取出 \(q_1,q_2\) 隊尾元素中的較強者作為最強蛇,以及 \(q_1\) 隊首元素作為最弱蛇,由於這一部分中所有最強蛇吃完最弱蛇後,都不是最弱蛇,因此這一輪的最弱蛇肯定沒有吃過別人,即,在佇列 \(q_1\) 中。
- 我們計算出最強蛇吃完最弱蛇的實力,如果小於現在 \(q_1\) 隊首的實力就進入第二部分,否則將它塞入 \(q_2\) 隊首。根據之前的推論,此時吃完最弱蛇的最強蛇的實力,肯定比上一輪吃完最弱蛇的最強蛇實力更菜。
- 第二部分:
- 我們直接取出 \(q_1,q_2\) 的隊尾,由於最弱蛇就是上一輪中吃完最弱蛇的最強蛇,因此我們不用取出 \(q_1/q_2\) 的隊首元素,而是直接取出上一次吃掉別人的蛇即可。
- 還是計算出最強蛇吃完最弱蛇的實力,如果此時這條蛇的實力比當前最弱蛇的實力強就退出,根據第二部分輪數的奇偶性判斷是否令答案減一。否則繼續重複上一步的過程。
時間複雜度 \(\sum n\)。
const int MAXN=1e6;
int n,a[MAXN+5];bool fst=0;
deque<pii> q1,q2;
pii getmx(){
pii p;
if(q1.empty()) return p=q2.back(),q2.ppb(),p;
if(q2.empty()) return p=q1.back(),q1.ppb(),p;
if(q2.back()>q1.back()) return p=q2.back(),q2.ppb(),p;
return p=q1.back(),q1.ppb(),p;
}
void solve(){
if(!fst){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
} else {
int c;scanf("%d",&c);
while(c--){
int x,y;scanf("%d%d",&x,&y);
a[x]=y;
}
} fst=1;
while(!q1.empty()) q1.ppb();
while(!q2.empty()) q2.ppb();
for(int i=1;i<=n;i++) q1.push_back(mp(a[i],i));
// for(int i=1;i<=n;i++) printf("%d%c",a[i]," \n"[i==n]);
while(1){
if(q1.size()+q2.size()<=2) return puts("1"),void();
pii p=getmx();
int y=q1.front().fi;q1.pop_front();
if(q1.empty()||mp(p.fi-y,p.se)<q1.front()){
int cnt=0,res=q1.size()+q2.size()+1,pre=p.fi-y;
while(1){
cnt++;
if(q1.size()+q2.size()<2){
if(cnt&1) res++;
printf("%d\n",res);
return;
} pii nwp=getmx();
if((q1.empty()||mp(nwp.fi-pre,nwp.se)<q1.front())&&
(q2.empty()||mp(nwp.fi-pre,nwp.se)<q2.front()));
else {
if(cnt&1) res++;
printf("%d\n",res);
return;
} pre=nwp.fi-pre;
}
} else q2.push_front(mp(p.fi-y,p.se));
} assert(0);
}
int main(){
// freopen("snakes4.in","r",stdin);
int qu;scanf("%d",&qu);
while(qu--) solve();
return 0;
}