不会贪心和 dp 啊(utpc2021 E)

luogu / pjudge

题意:\(n\) 个点,权值 \(x,y,c\),选 \(m\) 个,\(S\) 为选出的集合。最大化 \(\max p_x-\min p_x+\max p_y-\min p_y+\sum p_c(p\in S)\)

\(n,m\le 2e5\)

这是蓝。这是蓝。这是蓝。如此水平,令人汗颜!

有一个重要的性质:

\(m\gt 4\) 时,按 c 排序后前 \(m-4\) 大的一定会选。

证明:反证,题目相当于选 4 个点加上 \(x,-x,y,-y\) 的贡献。那当 \(m\gt 4\) 时一定有没有贡献进去的点,将其调整为 c 更大的点显然更优。

然后似乎就做完了?问题转化为了 \(m \le 4\)

直接 dp,\(f_{i, j, k}\) 表示前 \(i\) 个,选了 \(j\) 个,贡献集合状态为 \(k\) 的最大值。

其中 \(k\lt 16\),代表的是目前选的里面是否有贡献给那 4 个 max 和 min。

目标:\(f_{n,m,15}\)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;

#define pb push_back
#define pc putchar
#define sp pc(' ')
#define et pc('\n')
#define debug cerr<<"--ERROR--\n"
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
#define mem(a, x) memset(a, x, sizeof(a))
#define in(a, n) rep(i, 1, n) a[i]=rd()
#define all(x) x.begin(), x.end()

inline ll rd(){ll x=0; int f=1; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-48; c=getchar();} return x*f;}
inline void wr(ll x){if(x<0) putchar('-'), x=-x; static int stk[35]; int tp=0; do stk[tp++]=x%10;while(x/=10); do pc(stk[--tp]^48);while(tp);}

//const ldb eps = 1e-9;
const ll INF = 0x3f3f3f3f3f3f3f3f;
//const int mo = 1e9+7;
const int N = 2e5+3;
const int ALL = 15;
const int M = 4;

int n, m;
struct node {
	int x, y, c;
	bool operator < (const node &o) const {return c < o.c;}
} a[N];
ll f[N][M+1][ALL+1], s[N][ALL+1], sum, minx, maxx, miny, maxy;
// 0 : Xmax, 1 : Xmin, 2 : Ymax, 3 : Ymin

void clear() {  }
void chkmax(ll &a, ll b) {
	a = b>a ? b : a;
}
void chkmin(ll &a, ll b) {
	a = b<a ? b : a;
}
signed main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);

int TT = 1;
//TT = rd();
while(TT--)
{
	clear();
	cin >> n >> m;
	rep(i, 1, n) a[i].x=rd(), a[i].y=rd(), a[i].c=rd();
	sort(a+1, a+n+1);
	minx = miny = INF, maxx = maxy = 0;
	const int lim = min(M, m);
	rep(i, n-(m-lim)+1, n) chkmin(minx, a[i].x), chkmax(maxx, a[i].x), chkmin(miny, a[i].y), chkmax(maxy, a[i].y), sum += a[i].c;
	n -= m-lim, m = lim;
	rep(i, 1, n) {
		rep(j, 0, ALL) {
			ll &c = s[i][j];
			c = a[i].c;
			if(j & 1) c += a[i].x;
			if(j & 2) c -= a[i].x;
			if(j & 4) c += a[i].y;
			if(j & 8) c -= a[i].y;
		}
	}
	rep(j, 0, ALL) {
		ll &c = s[0][j];
		c = sum;
		if(j & 1) c += maxx;
		if(j & 2) c -= minx;
		if(j & 4) c += maxy;
		if(j & 8) c -= miny;
	}
	mem(f, -INF);
	rep(i, 0, n) rep(j, 0, ALL) f[i][0][j] = s[0][j];
	rep(i, 1, n) {
		rep(j, 1, m) {
			rep(k, 0, ALL) {
				chkmax(f[i][j][k], f[i-1][j][k]);
				chkmax(f[i][j][k], f[i-1][j-1][k] + s[i][0]);
				for(int S = ALL-k, T = S; T; T = (T-1)&S) {
					chkmax(f[i][j][k|T], f[i-1][j-1][k] + s[i][T]);
				}
			}
		}
	}
	wr(f[n][m][ALL]);
    et;
}
    return 0;
}

翻了一堆代码没一个看懂的,状压还是得自己写啊。/fendou

posted @ 2024-11-27 23:27  lowbit  阅读(27)  评论(0)    收藏  举报