「CF1517G」 Starry Night Camping

题意

平面上有 \(n\) 个点,给出点的坐标和权值 \(w_i\)。你需要删去一些点,使得对于每个点 \((x,y)\),不存在另三个点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\) 满足:

  • 对于所有 \(j\in\{1,2,3\}\)\(|x_j−x|,|y_j−y|\le1\)

  • 四点构成一个平行四边形(包括矩形),并有一条边平行于 \(x\)

求删完后点权和最大值。

分析

考虑形成的四边形的形态,发现可以把点按照横纵坐标的奇偶分成四类,偶数标为 \(o\),奇数标为 \(e\),则有 \((e,e),(o,e),(e,o),(o,o)\) 这几种,下面把这四个点集里的点分别记为 \(A,B,C,D\)

显然,每个符合条件的四边形都可以表示为一条 \(A\to B\to C\to D\) 的路径,肯定包含了一个“特殊点”,所以题目中的“特殊点”对答案没有影响。

我们的目的是把每一个这样的四边形中的一个点删掉,让删掉的权值最小,想到可以用最小割。

  • 建立 \(A\to B,B\to C,C\to D\) 的边,边权为正无穷;

  • 建立 \(s\to A,D\to t\) 的边,边权为正无穷;

  • 把每个 \(i\) 拆成 \(i\)\(i'\),建立 \(i\to i'\) 的边,边权为 \(w_i\)

这样做到只能割 \(i\to i'\) 的边,且满足每个点最多删一次,直接跑最小割就行了。

Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
// static char buf[100],*p1=buf,*p2=buf,obuf[100],*p3=obuf;
// #define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++
// #define putchar(x) (p3-obuf<100)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
mt19937_64 rnd(chrono::system_clock::now().time_since_epoch().count());
#define dbg(x) cout<<#x<<": "<<x<<"\n"
#define usetime() printf("time: %.3lfs\n",clock()*1.0/CLOCKS_PER_SEC)
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
inline void write(ll x){if(!x){putchar(48);putchar('\n');return;}short top=0,s[40];if(x<0)x=-x,putchar(45);while(x)s[top++]=x%10^48,x/=10;while(top--)putchar(s[top]);putchar('\n');}
namespace tobe{
	const ll maxn=2e3+5,maxm=1e6+5,mod=998244353;
	ll n,s,t,head[maxn],tot=1,sum,now[maxn],lvl[maxn];
	struct point{
		ll x,y,w;
	}p[maxn];
	struct edge{
		ll to,nxt,val;
	}e[maxm];
	vector<ll>S[5];
	inline void add(ll u,ll v,ll w){
		e[++tot]={v,head[u],w};
		head[u]=tot;
		e[++tot]={u,head[v],0};
		head[v]=tot;
	}
	inline bool bfs(){
		memset(lvl,0,sizeof(lvl));lvl[s]=1;
		queue<ll>q;q.push(s);now[s]=head[s];
		while(!q.empty()){
			ll u=q.front();q.pop();
			for(ll i=head[u];i;i=e[i].nxt){
				ll v=e[i].to,w=e[i].val;
				if(w>0&&!lvl[v]){
					lvl[v]=lvl[u]+1;
					q.push(v);now[v]=head[v];
					if(v==t)return 1;
				}
			}
		}
		return 0;
	}
	inline ll dfs(ll u,ll f){
		if(u==t)return f;
		ll tmp=f;
		for(ll i=now[u];i&&tmp;i=e[i].nxt){
			now[u]=i;
			ll v=e[i].to,w=e[i].val;
			if(w&&lvl[v]==lvl[u]+1){
				ll k=dfs(v,min(w,tmp));
				if(!k)lvl[v]=0;
				e[i].val-=k,e[i^1].val+=k;
				tmp-=k;
			}
		}
		return f-tmp;
	}
    inline void mian(){
		n=read(),s=0,t=n*2+1;
		for(ll i=1;i<=n;++i){
			p[i]={read(),read()};
			ll w=read();sum+=w;
			if((p[i].x&1)==1&&(p[i].y&1)==1)S[1].push_back(i);
			if((p[i].x&1)==0&&(p[i].y&1)==1)S[2].push_back(i);
			if((p[i].x&1)==0&&(p[i].y&1)==0)S[3].push_back(i);
			if((p[i].x&1)==1&&(p[i].y&1)==0)S[4].push_back(i);
			add(i,i+n,w);
		}
		for(auto i:S[1])add(s,i,INT_MAX);
		for(auto i:S[4])add(i+n,t,INT_MAX);
		for(ll k=1;k<=3;++k)
			for(auto i:S[k])
				for(auto j:S[k+1])
					if(abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y)<=1){
						add(i+n,j,INT_MAX);
					}
		ll ans=0;
		while(bfs())ans+=dfs(s,INT_MAX);
		write(sum-ans);
	}
}
signed main(){
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ll t=1;
	while(t--)tobe::mian();
	// fwrite(obuf,p3-obuf,1,stdout);
	return 0;
}
posted @ 2024-12-20 15:33  run-away  阅读(13)  评论(0)    收藏  举报