這道題我調了好久…細節非常多。
首先,看完題目後,可以發現這是一道博弈問題。
那麼接下來,我們假設最強蛇為 x
xx ,最弱蛇為 y
yy ,那麼這裡就有兩個結論:
如果 x
xx 吃了 y
yy 不是最弱的蛇,則 x
xx 必吃 y
yy 。
證明:假設當前第二強的蛇為 a
aa ,第二弱的蛇為 b
bb ,那麼 x
>
a>
b>y,
x−
y>
bx>a>b>y,x-y>b
x>
a>
b>y,
x−y>
b ,那麼假設 x
xx 吃了 y
yy 之後變成了 z
zz ,那麼此時有 z
>
bz>b
z>
b (這裡 z
zz 和 a
aa 的大小不能確定,因為有可能最強蛇吃掉最弱蛇還是最強蛇) ,如果 z
>
az>a
z>
a ,那麼 z
zz 還是最強蛇,所以 x
xx 肯定要吃掉 y
yy ,畢竟吃完後選擇權還在 x
xx 手上;如果 a
>
za>z
a>
z ,那麼 a
>z=
x−
y>
ba>z=x-y>b
a>z=
x−y>
b ,由於 x
>
a>
b>
yx>a>b>y
x>
a>
b>
y ,假設 a
aa 吃了 b
bb 之後變成了 c
cc ,那麼有 z
>
cz>c
z>
c 。因此,如果 c
cc 不死,那麼 z
zz 不會死,可以放心吃;否則,a
aa 為了活命,不能吃掉 b
bb 變成 c
cc ,因此此時 x
xx 仍然可以吃 y
yy 。
所以綜上,如果 x
xx 吃了 y
yy 不是最弱的蛇,則 x
xx 必吃 y
yy 。
如果 x
xx 吃了 y
yy 之後變成最弱的蛇了,那麼要不要吃呢?
此時,我們就不能看 x
xx 的選擇了,而要看下一條蛇的選擇。此處令 f
ff 為第二強的蛇,g
gg 為第三強的蛇,如果 x
xx 吃了 y
yy 變成 z
zz ,那麼 z
zz 能不能活看 f
ff 。如果 f
ff 吃了 z
zz ,那麼 x
xx 不能吃 y
yy ;否則,f
ff 不吃 z
zz 那麼 x
xx 可以吃 y
yy。那麼 f
ff 吃不吃又是看誰的呢?假設 f
ff 吃掉最弱蛇不是最弱蛇,由上述結論 f
ff 可以吃最弱蛇;否則,這個問題就變成了 「如果 f
ff 吃了最弱蛇後變成了最弱蛇,那麼要不要吃呢?」此時,我們驚喜的發現這個問題變成了乙個遞迴問題!那麼 f
ff 吃不吃完全看 g
gg 的選擇, 可以推出:g
gg 吃 f
ff 不吃 x
xx 吃,g
gg 不吃 f
ff 吃 x
xx 不吃。因此,我們在程式中不斷遞迴就好,假設當前第 k
kk 強的蛇吃,那麼 k−1
k-1k−
1 不吃,k−2
k-2k−
2 吃,k−3
k-3k−
3 不吃…直到第 1 強的蛇為止。
因此思路就是:先執行結論 1 ,無法執行時根據結論 2 的結果判斷是否還能再吃 1 次,最後輸出答案。
而由於原序列已經有序,因此這道題我們可使用兩個雙端佇列 q1,
q2
q1,q2
q1,q
2 維護。首先所有蛇入隊 q1q1
q1,執行結論 1 時所有生成的新蛇從對頭入隊 q2q2
q2,每一次取出最大值和最小值判斷。當沒辦法再執行結論 1 時,跳至結論 2 遞迴再看一次能否再吃 1 條。這樣,時間複雜度為 o(t
n)
o(tn)
o(tn
) ,可以通過此題。
上**:
#include
using
namespace std;
const
int maxn=
1e6+10;
int t,n,a[maxn]
,q1[maxn][2
],q2[maxn][2
],l1,l2,r1,r2,ans;
//ans=被吃了幾條蛇
//q1[i][0]=q2[i][0]=值,q1[i][1]=q2[i][1]=編號
struct node
;int
read()
return sum;
}node get_max()
//取出最大值}if
(l1<=r1)
else
if(q1[r1][0
]==sum&&q1[r1][1
]>id)}if
(flag==
1) r1--
;else r2--
;return
(node);}
node get_min()
//取出最小值}if
(l1<=r1)
else
if(q1[l1][0
]==sum&&q1[l1][1
](flag==
1) l1++
;else l2++
;return
(node);}
void
solve1()
//結論 1
else
continue;}
else
//不能吃
else
if(z.flag==1)
else
if(y.flag==1)
else
//塞回佇列裡面
return;}
}}bool
slove2
(int last)
//結論 2
else
if(l1<=r1&&
(x.sum-y.sum]||
(x.sum-y.sum==q1[l1][0
]&&q1[l1][1
]>x.id)))
else
return
!slove2
(last-1)
;//遞迴實現 }}
intmain()
else
} l1=
1;r1=
0;l2=n+
1;r2=n;
for(
int i=
1;i<=n;i++
) q1[
++r1][0
]=a[i]
;for
(int i=
1;i<=n;i++
) q1[i][1
]=i;
solve1()
;if(slove2
(n-ans)
) ans++
;//根據結論 2 看看能不能再吃一條
cout<"\n"
;//輸出存活蛇
}return0;
}
CSP S2020 貪吃蛇 題解
題意分析 給出乙個序列,以權值為第一關鍵字,編號為第二關鍵字單調遞增,每次操作讓最大元素的權值減去最小元素的權值,刪除最小元素,將最大元素插回序列並維護單調性,且每次操作要使當前最大元素操作後不必定被刪除,求最後最少能剩下幾個元素。思路分析 設原序列為 為了方便表述,本文對序列 中的元素的大小比較均...
利用Canvas js實現貪吃蛇 4
將貪吃蛇改造成物件導向,類似外掛程式的東西。過程中,要把握好this的指向,因為這個,除錯了好大會 將randfood進行了修正,新增了乙個配置引數與預設引數合併方法,其他的都還是一樣的。html 沒有改,在第一篇文章裡 附上 function tanchishe options this.sett...
用原生Canvas寫貪吃蛇及問題解決
為了學習canvas,寫了這個小遊戲貪吃蛇供自己和大家學習 github play on 遊戲截圖 前言 為了方便載入轉移,我把整個js都寫在了html裡,為了方便閱讀,將函式結構在html裡清晰地分開,並在 裡有足夠注釋。函式結構如下 script definations global snake...