傳送門
分析整個操作過程是什麼特點。如果之後有乙個長度比之前最短的還要短,那麼後面的統統截掉,相當於白給,所以,任何降序的操作都是無意義的。所以先利用單調棧處理出乙個嚴格單調上公升的序列(注意n
nn也要放進去,因為n
nn是初始長度)。
面對乙個單調上公升的序列,需要乙個方法來處理答案。考慮從長度為a→b
a\to b
a→b,則必定是長度為a
aa時的若干個迴圈加上乙個a
aa的字首構成長度為bbb。
而這樣的兩個部分可以看成是從b
bb拆開來的,乙個是a
aa的 ⌊ba
⌋\left\lfloor\frac\right\rfloor
⌊ab
⌋倍,乙個是b%a
b\%a
b%a的一倍。就可以轉化為兩個子問題遞迴,直到序列中找不到比當前要處理的數小的數為止。如圖,假設我想計算黑色長度變成紅色長度,怎麼做?
那麼,就是在黑色長度複製幾段到剩餘的小於黑色長度為止,即如圖框內。那麼也就是4
44次的黑色長度加上方框長度即所求的,然後繼續向小的遞迴即可。每次都記錄當前這段的權值也就是計算次數即可。
最後答案上區間加的時候差分一下即可。這就是大體的思路,具體細節看注釋。
對於t le
tletl
e,深有感觸。(屬於個人腦抽,不喜勿噴,可跳過)
我在主函式裡就放了乙個函式,直接從最大的那個開始分,然後每次分兩個解決。結果是,同乙個數可能在搜尋樹上出現多次,導致無意義的多算,參考了別人的acac
ac**後,發現對於每乙個數都只需要把它的餘數進行遞迴處理即可,本身只要將權值加到下乙個就可以了,然後加了乙個t
tt才過的。
反思:這是乙份tle
\color
tle的**。
#include
#define ll long long
using
namespace std;
ll read()
while
(ch>=
'0'&&ch<=
'9')
return w*f;
}const
int maxn=
1e5+10;
ll q,ans[maxn]
,st[maxn]
,tim[maxn]
;int n,q,m,cnt=0;
ll find
(ll x)
return ans;
}//查詢比x小的最大的數
void
solve
(ll x,ll t)
//如果小到連最小的數都無法歸約了,就可以直接加在序列上。
//簡言之,就是乙個序列就可以包含的,肯定不會造成更多的影響
int id=
find
(x);
// cerr
+=x/st[id]
*t;//在找到的這個數中加入次數
solve
(x%st[id]
,t);
//繼續遞迴求解
}//表示解決t次的長度為x的函式
intmain()
// for(int i=1;i<=cnt;i++) cerr
;//最大的只要1次
for(
int i=cnt;i>=
2;i--
) tim[i-1]
+=st[i]
/st[i-1]
*tim[i]
,//向下乙個傳遞次數
solve
(st[i]
%st[i-1]
,tim[i]);
//遞迴解決餘數,看是否可以 歸約到更小的序列中的數解決
solve
(st[1]
,tim[1]
);//最後解決最小的數
for(
int i=
1;i<=n;i++
) ans[i]
+=ans[i-1]
;//差分還原
for(
int i=
1;i<=n;i++
)printf
("%lld\n"
,ans[i]);
}
思路顯亂,望包含。 二分 單調棧 SPOJ MINSUB
題目 一開始並不會做,然後看了看下面的題解 然後大體思想理解了,之前寫單調棧一直都是用stack,node裡記錄向前延伸向後延伸以及當前的數值和位置,寫這個題的時候覺得用這種方法寫起來比較麻煩,然後嘗試去使用題解中的方法,單調棧可以像這篇題解中使用乙個陣列來模擬棧,同時分兩次遍歷陣列並統計每個元素的...
week5作業 單調棧 差分與字首和 尺取法
給定乙個直方圖,求直方圖中可連成的最大矩形面積 問題核心 單調遞增棧 利用單調遞增棧維護各個下標 左端點下標,利用各個高度判斷大小關係 面積 下標之差 高度 注意資料範圍,本題需使用long long include include using namespace std const int max...
10 29 T1 max 單調棧 貢獻法 二階差分
對於每個i用單調棧求出小於i的第乙個比他大的數l i 以及大於i的第乙個比他大的數r i i一定是l i r i 中最大的數,1 a 1分別加 1 a 1 a i a 2 b 1加 a 1 a i a 2 a b 1 遞減加 用二階差分o 1 完成修改 用兩遍字首和求出答案 include incl...