【带权二分】记录一些带权二分的一些题目

RT 带权二分主要是处理问题如在物品中选择k个,或者分k组,这些问题都有一个共性就是选得越多越好(满足单调性质)。对于平常的处理方法我们都是利用dp处理,将选择多少个作为一维度,但是在有些情况下,时空复杂度是容不下的。由于其具有单调性,那么我们可以利用决策单调性(或者斜率优化),或者用同样利用到单调性的二分来处理(有些时候要一起用到orz)。基本思想就是将原本越多越好的二分加上一些代价,使得并不能选得越多越好,而是在满足dp下优先选出最好的一些,当二分达到某个值的时候,也就满足了恰好k个或k组的限制条件。

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),那么这个东西显然满足考虑决策单调性来搞,决策单调性就是dp决策点单调不减。 搞一个二分单调队列,满足每个都管一段区间,且越队尾越管后面,也就是维护一个凸壳。感性理解就是再多加一个东西使得答案变得更优速度更慢,对于本题就是一个分组里的鱼变多使得答案更好的速度更慢,具体证明?orz orz  orz ,遇到写个暴力dp看一下是不是决策单调就好,或者用用四边形不等式orz.
#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);
}
 
posted @ 2018-12-31 14:23  Newuser233  阅读(7)  评论(0)    收藏  举报