高维前缀和 (SOSDP)
介绍
一维前缀和 :
二维前缀和:
当然也可以这么写:
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) a[i][j] += a[i - 1][j]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) a[i][j] += a[i][j - 1];
for(int i[1] = 1; i[1] <= n; i[1]++) for(int i[2] = 1; i[2] <= n; i[2]++) //... a[i[1]][i[2]][i[3]] ... += a[i[1] - 1] ...; for(int i[1] = 1; i[1] <= n; i[1]++) for(int i[2] = 1; i[2] <= n; i[2]++) //... a[i[1]][i[2]][i[3]] ... += a[i[1]][i[2] - 1] ...; ...
例题
Ⅰ. P5495 Dirichlet 前缀和
根据唯一分解定理,将每个素数看成一维,然后相当于是子集和,用高维前缀和即可。状态压缩,可以仔细思考。
#include<bits/stdc++.h> using namespace std; const int N = 2e7 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } #define uint unsigned int uint seed; inline uint getnext(){ seed ^= seed << 13; seed ^= seed >> 17; seed ^= seed << 5; return seed; } bool _u; int n; uint b[N], ans; bool ispri[N]; bool _v; int main(){ cerr << abs(&_u - &_v) << " MB\n"; n = read(), seed = read(); for(int i = 1; i <= n; ++i) b[i] = getnext(); ispri[1] = 1; for(int i = 1; i <= n; ++i){ if(!ispri[i]) for(int j = i; j <= n; j += i) b[j] += b[j / i], ispri[j] = 1; ans ^= b[i]; } printf("%lld\n", ans); return 0; }
Ⅱ. [ARC100E] Or Plus Max
将题目转成对于每个
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = (1 << 19) + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n; ll ans; struct node{ ll x, y; node operator + (const node &p){ node z; if(x > p.x) z.x = x, z.y = max(y, p.x); else z.x = p.x, z.y = max(x, p.y); return z; } }a[N]; bool _v; int main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; n = read(); for(int i = 0; i < (1 << n); ++i) a[i].x = read(), a[i].y = -1e18; for(int i = 0; i < n; ++i) for(int j = 0; j < (1 << n); ++j) if(j & (1 << i)) a[j] = a[j] + a[j ^ (1 << i)]; for(int i = 1; i < (1 << n); ++i){ ans = max(ans, a[i].x + a[i].y); printf("%lld\n", ans); } return 0; }
Ⅲ.CF1208F Bits And Pieces
我们可以枚举
#include<bits/stdc++.h> #define pii pair<int, int> #define fi first #define se second using namespace std; const int N = 2e6 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n; int a[N]; pii dp[N]; void add(int x, int id){ if(dp[x].fi < id) dp[x].se = dp[x].fi, dp[x].fi = id; else dp[x].se = max(id, dp[x].se); } void merge(int x1, int x2){ if(x1 > 2e6 || x2 > 2e6) return ; add(x1, dp[x2].fi), add(x1, dp[x2].se); } bool _v; signed main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; memset(dp, -1, sizeof(dp)); n = read(); for(int i = 1; i <= n; ++i) a[i] = read(), add(a[i], i); for(int i = 0; i < 21; ++i) for(int j = 0; j <= 2e6; ++j) if(!(j & (1 << i))) merge(j, j ^ (1 << i)); int ans = 0; for(int i = 1; i <= n - 2; ++i){ int lim = (1 << 21) - 1; int cur = a[i] ^ lim, res = 0; for(int j = 20; ~j; --j) if(cur & (1 << j) && dp[res ^ (1 << j)].se > i) res ^= (1 << j); ans = max(ans, res | a[i]); } printf("%d\n", ans); return 0; }
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17741614.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步