題目:
首先,處理出異或字首和 s[i],i 位置的答案就是 s[j] + s[j]^s[i],j <= i
異或的套路是按位考慮,但是這裡有加法...怎麼考慮進製?
所以就不能考慮答案的這一位是什麼,而應該考慮在這一位上的貢獻,那麼即使進製了,還是各位算各位的貢獻,互相獨立;
然後發現,如果 s[i] 在第 k 位上是1,那麼 s[j] 的第 k 位無論是0還是1,總體的貢獻都是 1<< k;
而如果 s[i] 在第 k 位上是0,那麼如果有乙個 s[j] 的第 k 位是1,總體貢獻就是 2 * (1<
於是現在問題變成在 j <= i 中找到第 k 位是1的 s[j],並且還要根據情況,對前面的位有限制;
這個不太好做,不妨變成在第 k 位是1(並且滿足前面位的限制)的所有位置中,找到最靠前的位置 l,看是否 l <= i;
由於只限制某些位是1,其它位隨便,符合了超集的概念,所以用高維字首和維護滿足每種限制的位置集合中最靠前的位置即可!
真是巧妙的思路,經典的應用!
(為什麼處理最高位+1的 l 就秒wa,而直接做到20就a了?l 好像也沒有處理錯啊...)
**如下:
#include#include#include
#include
using
namespace
std;
intconst xn=(1
<<20
);int n,l,s[xn],f[xn],bin[25
];int
rd()
while(ch>='
0'&&ch<='
9')ret=(ret<<3)+(ret<<1)+ch-'
0',ch=getchar();
return f?ret:-ret;
}void
init()
intmain()
for(int i=0;i)
for(int j=0;j<(1
<)
if(!(j&bin[i]))f[j]=min(f[j],f[j|bin[i]]);
for(int i=1;i<=n;i++)
if(f[t|bin[j]]<=i)ans+=bin[j+1],t|=bin[j];
}printf(
"%d\n
",ans);
}return0;
}
bzoj 5092 分割序列(貪心 高維字首和)
傳送門biu 對b序列求字首亦或和a,求對於每乙個i,a i a j a j 的最大值。可以把每個a i 看成各個二進位制位的集合。對於第i個字首a i 考慮a i 每乙個二進位制位對答案的貢獻。如果a i 的第j位為1,那麼這一位對答案的貢獻一定為1 如果a i 的第j位為0,那麼這一位對答案的貢...
bzoj1048 HAOI2007 分割矩陣
將乙個a b 的數字矩陣進行如下分割 將原矩陣沿某一條直線分割成兩個矩陣,再將生成的兩個矩陣繼續如此分割 當然也可以只分割其中的乙個 這樣分割了 n 1 次後,原矩陣被分割成了 n 個矩陣。每次分割都只能沿著數字間的縫隙進行 原矩陣中每一位置上有乙個分值,乙個矩陣的總分為其所含各位置上分值之和。現在...
BZOJ1048 HAOI2007 分割矩陣
將乙個a b的數字矩陣進行如下分割 將原矩陣沿某一條直線分割成兩個矩陣,再將生成的兩個矩陣繼續如此 分割 當然也可以只分割其中的乙個 這樣分割了 n 1 次後,原矩陣被分割成了n個矩陣。每次分割都只能 沿著數字間的縫隙進行 原矩陣中每一位置上有乙個分值,乙個矩陣的總分為其所含各位置上分值之和。現在需...