[atAGC062D]Walk Around Neighborhood
记,则无解当且仅当
结论: 当且仅当(其中)
必要性:根据,显然成立
充分性:根据对称性,不妨假设
- 若,则取即可
- 若,则取 即可
由于构成正方形,进而的取值构成区间,即得证
根据结论,问题即转化为以下形式:
选择排列和,要求,并最小化
二分枚举答案,显然有解的必要条件为
当确定后,每个的取值构成区间,转移为
- 对于,必然可以转移,且时转移后为
- 对于,转移时需有,且转移后为
取分别为最小/最大的满足,则应有,且其余均存在合适的位置
可以贪心取为的最、次小值(若唯一则均为),即转化为对的背包
具体的,记,即判断是否存在子集和
当区间长度时必然有解,进而,放缩得
根据经典结论,不同的个数为,并可以利用加入过程将二分改为枚举,时间复杂度为
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2022-06-30 [loj6746]区间众数
2021-06-30 [loj3031]聚会
2021-06-30 [loj3146]路灯