BZOJ 4942 NOI2017 整數 分塊

2022-04-02 14:22:49 字數 1464 閱讀 4060

bzoj

洛谷uoj

可能是退役之前最後乙個bzoj rank1了?

參考這裡。

如果沒有減法,對乙個二進位制數暴力進製,均攤複雜度是\(o(1)\)的(要進\(o(n)\)次位就至少需要\(o(n)\)次操作)。

但是這題有減法...顯然暴力進製就不對了。

那麼我們把減法變成加法,分別維護加上的數\(inc\)和減掉的數\(dec\)是多大。查詢時顯然不能直接兩位相減,要判斷一下後面是否需要進製。

對此用\(set\)維護一下\(inc,dec\)所有不同位的位置,找到查詢位後面第乙個不同的位置,判一下大小關係就可以了。

關於維護進製,比較顯然的是拿線段樹維護每一位的情況,把\(a\times2^b\)拆成\((2^+2^+...)2^n\)。。這樣就成兩個\(\log\)了(╯‵□′)╯︵┻━┻。

注意到\(a\)不算大,而且線段樹的每個位置是可以表示\(16\)或\(32\)位的。直接把\(a\)左移\(b\)位(本來就是= =),也就是把\(a\)加到\(b\)那個位置即可。如果取\(32\)位這麼加一次顯然是只會進製一次的(最多影響兩個位置)。

(\(32\)位可以直接用unsigned int,自然溢位就可以得到加之後這幾位的值,判斷是否進製就判一下這個數加之前與加之後的大小關係即可)

注意到這個線段樹其實沒什麼必要。分塊,每塊維護\(32\)位的值,每次只要在對應塊上加,然後暴力進製即可。

複雜度\(o(n\log n)\)(set...)。

另外移位不能\(\geq\)位寬,所以移\(32\)位拆成移\(31\)位再移\(1\)位好了。。

//18148kb	3740ms

#include #include #include #include #define pc putchar

#define gc() getchar()

#define maxin 300000

//#define gc() (ss==tt&&(tt=(ss=in)+fread(in,1,maxin,stdin),ss==tt)?eof:*ss++)

typedef long long ll;

typedef unsigned int uint;

const int n=1e6+5;

uint inc[n],dec[n];

std::setst;

char in[maxin],*ss=in,*tt=in,out[n<<1],*o=out;

inline int read()

void modify(uint a,uint b,uint *a,uint *b)//a在傳參前就要取abs啊(uint)

*o++='\n';

}int main()

fwrite(out,1,o-out,stdout);

return 0;

}

bzoj3936 Noi2017 蔬菜 貪心

題目描述 題解 這道題可以從後往前貪心。若我們知道了第i的答案,我們只要去掉 當前個數 前i 1天能取的個數 個價值最小的蔬菜,就能得到第i 1天的答案。所以我們現在只要求出最後一天的答案。把每種蔬菜拆成兩份,前c 1個價值為a,最後乙個價值為a s 按變質的順序 放入優先佇列中,依次取出來放入還能...

刷題 BZOJ 4946 Noi2017 蔬菜

網上大部分都是並查集寫法,但是有大神寫了非並查集寫法,特別容易理解 首先 s i 的限制,只需將每乙個蔬菜分出乙個價值為 a i s i 且過期時間為該蔬菜最晚的一天的蔬菜 把時間倒序之後,問題轉化為每個蔬菜會在第幾天出現,每天貪心選擇價值最大的即可 先求出 max 的答案,然後遞推 1,max 1...

NOI2017 蚯蚓排隊

嘟嘟嘟 現在看來這道題還不是特別難。別一看到字串就想sam 看到 k 很小,所以我們可以搞乙個單次修改複雜度跟 k 有關的演算法。能想到,每一次斷開或鏈結,最多隻會影響 k 2 個長度為 k 的區間。所以我們開乙個雜湊表,每一次拼接時就往雜湊表裡加入 k 2 個新的雜湊值,斷鏈的時候就把這些雜湊值減...