【带权二分】记录一些带权二分的一些题目
RT
带权二分主要是处理问题如在物品中选择k个,或者分k组,这些问题都有一个共性就是选得越多越好(满足单调性质)。对于平常的处理方法我们都是利用dp处理,将选择多少个作为一维度,但是在有些情况下,时空复杂度是容不下的。由于其具有单调性,那么我们可以利用决策单调性(或者斜率优化),或者用同样利用到单调性的二分来处理(有些时候要一起用到orz)。基本思想就是将原本越多越好的二分加上一些代价,使得并不能选得越多越好,而是在满足dp下优先选出最好的一些,当二分达到某个值的时候,也就满足了恰好k个或k组的限制条件。
显然满足考虑决策单调性来搞,决策单调性就是dp决策点单调不减。
搞一个二分单调队列,满足每个都管一段区间,且越队尾越管后面,也就是维护一个凸壳。感性理解就是再多加一个东西使得答案变得更优速度更慢,对于本题就是一个分组里的鱼变多使得答案更好的速度更慢,具体证明?orz orz orz ,遇到写个暴力dp看一下是不是决策单调就好,或者用用四边形不等式orz.
BZOJ2151种树
题意:有n 2e5颗树围成一圈,选每颗树有价值,不能选择相邻的两棵树,求恰好选m颗的价值 f[i][1/0][1/0]讨论到第i个,第i个选了没有,第一个选了没有。二分代价加到每颗树的价值上,记得记录下选了多少个。 !!!提示:在hdhd大神的hack之下,发现一个大漏洞,就是这里的二分范围。范围不能开太小了,开成[-1000,1000]是错误的。实际上大概应该开成绝对值之和?本题数据水,一组hdhd大神样例: 6 3 -1000 1000 -1000 -1000 1000 -1000#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
typedef double db;
const int maxn = 200005;
struct oo{
int v; int x;
}f[maxn][2][2];//前i个第i个选了没第1个选了没
bool operator<(const oo&x,const oo&y) {
if(x.v!=y.v) return x.v < y.v;
return x.x > y.x;
}
using namespace std;
int n,m,a[maxn];
int as;
bool dp(int ct) {
memset(f,0,sizeof f);
f[1][1][1] = {a[1]-ct,1}; f[1][0][1] = f[1][1][0] = {-0x3f3f3f3f,0};
for(int i=2;i<=n;i++) {
f[i][0][0] = max(f[i-1][1][0],f[i-1][0][0]);
f[i][0][1] = max(f[i-1][1][1],f[i-1][0][1]);
f[i][1][0] = f[i-1][0][0]; f[i][1][0].v += a[i] - ct; f[i][1][0].x++;
f[i][1][1] = f[i-1][0][1]; f[i][1][1].v += a[i] - ct; f[i][1][1].x++;
}
oo ans = max(f[n][1][0],max(f[n][0][1],f[n][0][0]));
if(ans.x<=m) { as = ans.v+ct*m; return 1; }
return 0;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
if(n/2<m) {
puts("Error!"); return 0;
}
int L = -20005; int R = 20005,mid;
while(L<=R) {
mid = (L+R)>>1;
if(dp(mid)) R = mid-1;
else L = mid+1;
}
printf("%d",as);
}
cf321E BZOJ5311贞鱼
题意:n个鱼选k个区间,每个区间有一个怨气值,求一种分区间方案使得怨气值总和最小。 带权二分消除掉选多少个区间的条件之后f[x] = min: f[y] + val(y+1,x),那么这个东西#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 4e3 + 5;
struct node{ int x,l,r; }qe[maxn];
int ql,qr;
int n,k;
int sm[maxn][maxn];
int g[maxn];
int val(int x,int y) { return ( sm[y][y] - sm[x-1][y] - sm[y][x-1] + sm[x-1][x-1] )/2; }
int f[maxn];
int calc(int x,int y) {
return f[x] + val(x+1,y);
}
int better(int x,int y,int k) { // x better than y j
int fx = calc(x,k); int fy = calc(y,k);
if(fx<fy||(fx==fy&&g[x]<g[y])) return 1; return 0;
}
int binary(int i,int j) {
int l = qe[qr].l , r = n ,ans = 0;
while(l<=r){
int mid = (l+r)>>1;
if(better(i,j,mid)) ans = mid ,r = mid - 1;
else l = mid + 1;
}
return ans;
}
void solve(int ct) {
ql = qr = 1; qe[1] = (node){0,0,n};
for(int i=1;i<=n;i++) {
++qe[ql].l; if(qe[ql].l>qe[ql].r) ++ql;
f[i] = calc(qe[ql].x,i)+ct; g[i] = g[qe[ql].x]+1;
if(better(i,qe[qr].x,n)) {
while(ql<=qr&&better(i,qe[qr].x,qe[qr].l)) --qr;
if(ql>qr) qe[++qr] = (node){i,i,n};
else {
int x = binary(i,qe[qr].x);
qe[qr].r = x-1; qe[++qr] = (node){i,x,n};
}
}
}
}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
char t=GC;
int x=0;
while(!isdigit(t)) t=GC;
while(isdigit(t)) x=x*10+t-48,t=GC;
return x;
}
int main() {
n = R(); k=R();
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
sm[i][j] = R();
sm[i][j] += sm[i-1][j] +sm[i][j-1] -sm[i-1][j-1];
}
}
int L = 0; int R = 5000 , mid,ans = 0;
while(L<=R) {
int mid = (L+R)>>1;
solve(mid);
if(g[n]<=k) ans = mid , R = mid - 1; else L = mid + 1;
}
solve(ans);
printf("%d",f[n]-k*ans);
}

浙公网安备 33010602011771号