1 条题解

  • 0
    @ 2025-8-24 21:49:02

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar huangjinxiu
    祭天

    搬运于2025-08-24 21:49:02,当前版本为作者最后更新于2024-12-10 00:23:17,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    nn 很小,我们可以考虑 n3n^3 枚举三角形的 33 个顶点 然后快速计算答案。

    如上图,考虑答案为红点,即为总点数减去蓝点数。 凸包被分成了 44 个部分,其中有 33 个部分都是蓝点。 我们发现每个部分的蓝点是独立的,且只与三角形的一条边有关。

    考虑计算每条边对应区域的蓝点数。记 f[i][j]f[i][j] 表示位于 PiPj\overrightarrow {P_iP_j} 逆时针方向的所有点的权值和。发现若 PkP_k 位于 PiPj\overrightarrow {P_iP_j} 的顺时针方向,则答案单调不降(如上图)。于是我们可以先按照点关于 PiP_i 的相对位置排序(这个可以用叉积方便地判断),接着再双指针扫一遍即可得到 f[i]f[i] 的所有值。

    统计答案是简单的,题目中保证了顺时针给定凸包上的点,所以可以直接按序依次枚举。但需要注意如果有位置与凸包顶点重合的点用叉积判断其位置关系可能会炸掉。我们不妨再计算 ff 时先不考虑这些点,最后统计答案的时候再单独考虑这些点。

    时间复杂度 O(n3+nmlogm)O(n^3 + nm\log m) 代码如下(马蜂有点抽象

    #include<bits/stdc++.h>
    #define ld  int 
    #define pdd pair<ld,ld>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb emplace_back
    #define cmax(a,b) ((a)=max((a),(b)))
    using namespace std;
    namespace IO{
    	const int maxn=(1<<20);char *p1,*p2,buf[maxn];
    	#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,maxn,stdin),p1==p2)?EOF:*p1++)
    	int read(){
    		int f=1,k=0;char c;
    		while(!isdigit(c=gc()))if(c=='-')f=-1;
    		while(isdigit(c))k=k*10+c-48,c=gc();
    		return f*k;
    	}
    	void write(int k,char c){
    		if(k<0){putchar('-');k=-k;}
    		char st[21];int top=0;
    		do{st[++top]=(k%10)|48,k/=10;}while(k);
    		while(top)putchar(st[top--]);
    		putchar(c);
    	}
    }using namespace IO;
    const int N=605,M=1e4+10;
    int f[N][N],corner[N],x,y,z,n,m,sum,ans=-0x3f3f3f3f;
    pdd P[N],center;map<pdd,int> mp;
    struct V{pdd pos;int val;}v[M];
    inline int Cross(pdd x,pdd y){
    	return (x.fi-center.fi)*(y.se-center.se)-(x.se-center.se)*(y.fi-center.fi);
    }
    inline bool cmp(V x,V y){return Cross(x.pos,y.pos)<0;}//y位于x的顺时针方向 
    inline int nxt(int x){return x==n?1:x+1;}
    void pre_solve(int id){
    	center=P[id];
    	int val=0,l=1;
    	sort(v+1,v+1+m,cmp);
    	for(int j=nxt(id);j!=id;j=nxt(j)){
    		while(l<=m&&Cross(P[j],v[l].pos)>0)val+=v[l++].val;//v[l].pos位于P[j]的逆时针方向  
    		f[id][j]=val;
    	}
    }
    int solve(){
    	for(int i=1;i<=n;++i)
    		for(int j=i+1;j<=n;++j)
    			for(int k=j+1;k<=n;++k)
    				cmax(ans,sum-f[i][j]-f[j][k]-f[k][i]+corner[i]+corner[j]+corner[k]);
    	return ans;
    }
    signed main(){
    	n=read();
    	for(int i=1;i<=n;++i){
    		P[i].fi=read(),P[i].se=read();
    		mp[P[i]]=i;
    	}
    	m=read();
    	for(int i=1;i<=m;++i){
    		x=read(),y=read(),z=read();
    		v[i]={{x,y},z};
    		corner[mp[{x,y}]]+=z;
    		if(mp[{x,y}])--i,--m;
    		else sum+=z;
    	}
    	for(int i=1;i<=n;++i)pre_solve(i);
    	write(solve(),'\n');
    	return 0;
    }   
    
    • 1

    信息

    ID
    2519
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者