不会贪心和 dp 啊(utpc2021 E)
题意:\(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

浙公网安备 33010602011771号