sosdp(高維字首和)學習筆記

2022-09-20 14:09:08 字數 3102 閱讀 5617

我們先看一維字首和

for(int i=1;i<=n;i++)

s[i]+=s[i-1];

那麼二維字首和

for(int i=1;i<=n;i++)

for(int j=1;j<=n;j++)

s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];

這個是根據容斥計算的,維度很高的時候就不行了

我們換一種方法

for(int i=1;i<=n;i++)

for(int j=1;j<=n;j++)

s[i][j]+=s[i-1][j];

for(int i=1;i<=n;i++)

for(int j=1;j<=n;j++)

s[i][j]+=s[i][j-1];

也就是對每一維分別做字首和

那麼高維字首和呢?

它是解決以下問題的

已知乙個序列\(a_\),對於每乙個\(i\in0,n-1\)

求\[\sum_a_j

\]也就是求它的子集的權值和

直接子集列舉做是\(3^n\)的,我們需要更快的演算法

考慮剛才字首和的過程,發現對於二進位制而言,它的子集一定是它的字首和中的

因為一定會有某一位比這個數小,所以是字首和

但是我們不可能按照容斥做法做字首和,因此就對每一維做字首和

for(int i=0;i>i)&1) f[j]+=f[j-(1複雜度\(o(n2^n)\)

類似的,有下面的問題

已知乙個序列\(a_\),對於每乙個\(i\in0,n-1\)

求\[\sum_a_j

\]也就是詢問超集的權值和,對應到上面就是高維字尾和,和字首和是類似的

for(int i=0;i>i)&1)) f[j]+=f[j+(1因為差分和字首和是逆運算,所以就有了下面的**

for(int i=0;i>i)&1) f[j]-=f[j-(1這個東西又被稱作sosdp

題目傳送門

注意到我們只需要求出

\[i \;or j==k

\]的最大值,取個字首max就行了

但是這樣也不好求,我們考慮繼續轉化為

\[i\;or j\in k

\]也就是k的子集,這個東西顯然小於等於k,也是合法的

那麼i,j顯然也是k的子集,也就是說我麼需要從k的子集中挑出最大值和次大值就行啦

那麼我們知道字首和不僅可以知道「和」,也可以知道字首max之類的

那麼我們只需要對於每乙個k,求出他子集的最大和次大就可以了

可以用高維字首和

#includeusing namespace std;

const int n = 19;

const int m = (1

#define y(x) x.second

pii merge(pii a,pii b)

else y(res)=max(y(a),x(b));

return res;

}pii f[m];

int main()

else

}}int a[n];

int main()

for(int i=0;i<21;i++)

for(int j=0;j

if(!((j>>i)&1))

ans=max(ans,ans|a[i]);

} cout題目傳送門

很簡單,只需要判斷\(a_i\)的補集的子集是不是全為空就行了

#includeusing namespace std;

const int k =22;

const int n = 1e6+7;

int f[(1<>n;

for(int i=1;i<=n;i++)

for(int i=0;i<22;i++)

for(int j=0;j

if((j>>i)&1) up(j,f[j-(1題目傳送門

直接求不是很好求,考慮容斥

用總的單詞個數n,減掉乙個母音也沒包含的個數

乙個母音也沒包含,相當於是當前母音集合補集的子集

用高維字首和就可以處理了

#includeusing namespace std;

typedef long long ll;

const ll k =24;

const ll n = 1e6+7;

ll f[(1<>n;

for(ll i=1;i<=n;i++)

^n[i \& a_j ==i]\)

可以高維字首和處理

設\(g(i)\)為選出乙個子串行使得子串行\(j_1,j_2……\)

滿足\(i\in a_\&a_……\)的方案數

那麼顯然是\(2^-1\)

我們是\(h(i)\)為題目與的值是i的答案,題目所求即為\(h(0)\)

那麼\(g(i)=\sum_h(j)\)

也就是高維字尾和,我們直接來乙個高維字尾差分就可以的到h啦

#includeusing namespace std;

const int n = 1e6+7;

const int k = 20;

const int m = (1<>n;

pow[0]=1;

for(int i=1;i<=n;i++)

for(int i=0;i<20;i++)

for(int j=0;j

if(!((j>>i)&1))

f[j]=(f[j]+f[j+(1<>i)&1))

g[j]=(g[j]-g[j+(1<

cout<

return 0;

}

學習筆記 高維字首和

求 sum i n i a i 實際上,這只是高維字首和的一種特殊形式,即每一維的大小都為 2.我們計算矩陣字首和時,通常用的是容斥的方法.設當前要計算 d 維字首和,容斥的複雜度為 sum n binom 2 d 當維數過大時顯然不行.我們考慮計算矩陣字首和的另一種方法 先算出每一列的字首和,然後...

高維字首和

給定 num 個三元組 x,y,z 每次詢問滿足 x leq qx y leq qy z leq qz 的三元組個數。x,y,z leq n n leq 10 q num leq 10 6 容易想到維護 pre x,y,z 表示 x leq x y leq y z leq z 的三元組個數 思路1利...

SOS DP學習筆記

sum over subsets sos dp 給出乙個長度為 2 n 的陣列 a 對於每乙個 mask 2 n 要求計算出 f mask sum a sub 其中 sub in mask 表示 sub mask sub 1.暴力 for int mask 0 mask 1根據定義直接做,列舉所有小...