简单背包问题
01背包
scanf("%d%d", &n, &m); n种,限制最大m
for (int i = 1; i <= n; i++) {
scanf("%d%d", &w, &v); 重w,价值v
for (int j = m; j >= w; j--) { 从后向前遍历
dp[j] = std::max(dp[j], dp[j - w] + v);
}
}
01背包中物品只能取一次,从后向前遍历时的dp是上一个物品遍历后造成影响,而该物品的遍历未造成影响的
完全背包
for (int i = 1 ; i <= n ; i++) {
scanf("%d%d", &w, &v);
for (int j = w ; j <= m ; j++) { 从前向后遍历
dp[j] = std::min(dp[j], dp[j - w] + v);
}
}
完全背包中物品能取无数次,从前向后遍历时的dp是上一个物品和该物品的遍历均造成影响的
多重背包
for(int j=1;j<=n;j<<=1){ 二进制压缩,转换为01背包
++cnt;
b[cnt].h=h*j;
b[cnt].l=l;
n-=j;
}
if(n){
++cnt;
b[cnt].h=h*n;
b[cnt].l=l;
}
树状数组
适用范围:
1.单点修改,单点查询
2.区间修改,单点查询
3.区间查询,区间修改
单点修改,区间查询
inline int lowbit(int x) {
return x & -x;
}
void update(int x,int k,int n)
{
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=k;
}
int getsum(x){
int sum = 0;
for(int i=x;i;i-=lowbit(i)){
sum+=t[i];
}
return sum;
}
区间修改,单点查询
利用差分数组的性质,其前缀和即为该元素本身
update(l, x, n);
update(r + 1, -x, n);
区间修改,区间查询
构造差分数组sum1 [ n ], sum2 = sum1 [ i ] * i;( i 从1开始计数)
void update(ll p, ll x){
for(int i = p; i <= n; i += i & -i)
sum1[i] += x, sum2[i] += x * p;
}
void range_update(ll l, ll r, ll x){
update(l, x), update(r + 1, -x);
}
ll getsum(ll p){
ll res = 0;
for(int i = p; i; i -= i & -i)
res += (p + 1) * sum1[i] - sum2[i]; 重点!
return res;
}
ll range_getsum(ll l, ll r){
return getsum(r) - getsum(l - 1);
}
树状数组 数据结构详解与模板(可能是最详细的了)_bestsort的博客-CSDN博客_树状数组
线段树
线段树 从入门到进阶(超清晰,简单易懂)_繁凡さん的博客-CSDN博客_线段树
进阶算法,暂时搁置先推紫书去了,结束之后才觉得暑期集训如此短暂,ACM之路道阻且长