「在賭場裡,基本原則就是讓他們玩下去以及讓他們再來玩。他們玩得越久,他們會輸的越多,最後,我們會得到一切。」
(摘自2023年的電影casino)
你正在一家賭場的老虎ji面前,你的手上共有k
個遊戲幣。
當你每次按下老虎ji的按鈕時,它會隨機地報出乙個數字d
,如果d=0
,那麼什麼事情都不會發生;如果d>0
,那麼恭喜你,老虎ji會吐給你d
個遊戲幣;但是如果d<0
,很不幸,你將需要支付給老虎ji d
個遊戲幣。
這台老虎ji的工作原理很簡單,在老虎ji內部有乙個長度為n
的序列a[0],a[1],…,a[n−1]
,每當你按下按鈕時,如果你手上共有k
個遊戲幣,那麼它報出的數字d
就是a[kmodn]
。前幾次賭博讓你嘗到了甜頭,貪婪的慾望驅動著你不停地按下老虎ji的按鈕。當d<0
且你支付不了那麼多遊戲幣時,你宣告破產。請問在你破產的時候你一共按過多少次按鈕呢?
第一行包含乙個正整數t(1≤t≤5000)
,表示測試資料的組數。
每組資料第一行包含兩個正整數n,k(1≤n≤100000,1≤k≤1018)
,表示序列長度以及你初始的遊戲幣數量。
第二行包含n
個整數a[0],a[1],…,a[n−1](−109≤a[i]≤109)
。輸入資料保證所有資料中n
的總和不超過1000000
。對於每組資料輸出一行乙個整數,即你破產的時候你一共按過按鈕的次數。如果你運氣很好,永遠都不會破產,請輸出−1
。
15 20
-1 -2 3 4 -5
5顯然最普通的模擬方法肯定會超時
用另一種模擬方法 時間複雜度n
模擬第一輪 直到遇到迴圈 也就是第二次走到某個地方
然後就可以求出 一遍迴圈走的步數c 和一遍迴圈減小的數值d
顯然 如果d<=0那麼就是死迴圈 輸出-1即可
一開始:
當前k除 n*d 到k為負數
但是錯誤性很明顯:不可能每次都是迴圈結束才-k 很可能在迴圈的中間就已經減到負數了 所以cnt會偏大
調整:預留一次迴圈:就是把k變為k%d(之前的想法是把k變成負數) 預留最後一次迴圈自己模擬 正確性也很明顯
但是還有個bug
可能每次迴圈的差值d很小 但是在迴圈過程中 起伏非常大 在倒數第二遍或者。。。就已經被減為負數了
所以再調整:
求出d的最大連續和(我這裡求的是極限數值) 讓k比d大的時候開始最原始模擬
#includeusingview codenamespace
std;
//input
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define ri(n) scanf("%d",&(n))
#define rii(n,m) scanf("%d%d",&n,&m);
#define riii(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define rs(s) scanf("%s",s);
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,n) for(int i=0;i
#define clr(a,v) memset(a,v,sizeof a)
/////////////////////////////////
/#define n 100000+10ll a[n];
ll vis[n][2];
intmain()
if(!vis[pos][0
])
else
maxx=-maxx;
ll h=k/d;
cnt+=h*c;
k%=d;
while(k<=maxx)//
回補
while(1
)
}break
; }}}
}