[atAGC062D]Walk Around Neighborhood

D=max1indi,则无解当且仅当2D>i=1ndi

结论:(x,y),(X,Y),{|X|+|Y|=R|xX|+|yY|=d 当且仅当|rR|dr+R(其中r=|x|+|y|

必要性:根据|a||b||ab||a|+|b|,显然成立

充分性:根据对称性,不妨假设x,y0

  • d=r+R,则取(X,Y)=(R,0)即可
  • d=|rR|,则取(X,Y)={(x+(Rr),y)rR(x(rR),y)r>RrRx(0,y((rR)x))r>RrR>x 即可

由于{(X,Y)|X|+|Y|=R}构成正方形,进而|xX|+|yY|的取值构成区间,即得证

根据结论,问题即转化为以下形式:

选择排列diri,要求{r0=rn=0i[1,n],|ri1ri|diri1+ri,并最小化max1inri

二分枚举答案s,显然有解的必要条件为sD2

当确定di后,每个ri的取值构成区间,转移为[x,y][minxiy|id|,min(y+d,s)]

  • 对于ds,必然可以转移,且y=s时转移后为[max(xs,0),y]
  • 对于d>s,转移时需有yds,且转移后为[dy,s]

a,b分别为最小/最大的i满足di>s,则应有{i=1a1didasi=b+1ndidbs,且其余di均存在合适的位置

可以贪心取da,dbdi>s的最、次小值(若唯一则均为D),即转化为对dis的背包

具体的,记S=disdi,即判断是否存在子集和[das,S(dbs)]

当区间长度s时必然有解,进而S(dbs)(das)+1<s,放缩得S2D

根据经典结论,不同的di个数为O(D),并可以利用加入过程将二分改为枚举,时间复杂度为O(DD)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200005;
int n,s,ans,a[N],cnt[N],g[N<<1],f[N<<1];
ll sum;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		cnt[a[i]]++;
	}
	sort(a+1,a+n+1);
	for(int i=1;i<n;i++)sum+=a[i];
	if (sum<a[n]){
		puts("-1");
		return 0;
	}
	s=sum=0,ans=a[n],f[0]=1;
	for(int i=1;i<a[n];i++){
		if (cnt[i]){
			s+=cnt[i];
			if (sum<=(a[n]<<1)){
				for(int j=sum;j;j--)f[j]-=f[j-1];
			}
			sum+=(ll)i*cnt[i];
			if (sum<=(a[n]<<1)){
				int s=i*(cnt[i]+1);
				for(int j=0;j<=sum;j++)g[j]=f[j]+(j<i ? 0 : g[j-i]);
				for(int j=0;j<=sum;j++)f[j]=(g[j]>(j<s ? 0 : g[j-s]));
				for(int j=1;j<=sum;j++)f[j]+=f[j-1];
			}
		}
		if (i>=(a[n]>>1)){
			if (sum>(a[n]<<1)){ans=i;break;}
			int x=a[s+1]-i,y=sum-(a[min(s+2,n)]-i);
			if ((x<=y)&&(f[y]>f[x-1])){ans=i;break;}
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @   PYWBKTDA  阅读(112)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2022-06-30 [loj6746]区间众数
2021-06-30 [loj3031]聚会
2021-06-30 [loj3146]路灯
点击右上角即可分享
微信分享提示