我們先看一維字首和
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根據定義直接做,列舉所有小...