[bzoj3100]排列
来源:互联网 发布:淘宝导航栏代码生成器 编辑:程序博客网 时间:2024/06/10 04:20
题目大意
给定长度为N的序列,权值范围在[1,n]。
求一个长度最大的区间使该区间是一个包含1的排列。
n<=1e6,空间限制16M
做法
一个区间合法的条件?
1、包含1
2、所有元素互不相同
3、若长度为k,区间和为k*(k+1)/2
这样的区间的性质?
最大值等于区间长度。
这样的区间最大值可以在1左边或右边,做两次即可,下面假设最大值在1右边。
枚举每一个1,然后枚举右端点的位置(显然在该1右边)
假如枚举的右端点位置是r,1的位置是i,[i,r]最大值为mx。根据性质,现在枚举的区间就是[r-mx+1,r]。
为了满足条件2,我们需要预处理left表示一个数左边第一个和其相同的位置(这个预处理需要两个数组),那么我们求出[i,r]的left的max,便可以判断[r-mx+1,r]是否合法,同时为了满足条件3,需要用前缀和来计算。
复杂度显然线性。
前缀和数组应该是个long long算两个数组,加上原数组,计算left所用两个数组,总共是5个数组,boom。
原数组和前缀和数组显然可以共用,总共是4个数组,boom。
left不要预处理,即算即用,3个数组,可以。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=1000000+2;typedef long long ll;ll a[maxn];int last[maxn];int i,n,ans,mx,wz;void calc(){ int j,l; ans=max(ans,1); mx=1; l=last[a[i]-a[i-1]]; last[a[i]-a[i-1]]=i; wz=l+1; fo(j,i+1,n+1){ if (j>n||a[j]-a[j-1]==1) break; l=last[a[j]-a[j-1]]; last[a[j]-a[j-1]]=j; wz=max(wz,l); mx=max(mx,int(a[j]-a[j-1])); if (wz<=j-mx+1) if (a[j]-a[j-mx]==(ll)mx*(mx+1)/2) ans=max(ans,mx); } i=j;}int main(){ scanf("%d",&n); fo(i,1,n){ scanf("%d",&a[i]); //sum[i]=sum[i-1]+(ll)a[i]; //left[i]=last[a[i]]; //last[a[i]]=i; } fo(i,1,n) a[i]+=a[i-1]; fo(i,1,n){ if (a[i]-a[i-1]==1) break; last[a[i]-a[i-1]]=i; } while (i<=n){ calc(); } fd(i,n,1) a[i]-=a[i-1]; fo(i,1,n/2) swap(a[i],a[n-i+1]); fo(i,1,n) a[i]+=a[i-1]; fo(i,1,n) last[i]=0; fo(i,1,n){ if (a[i]-a[i-1]==1) break; last[a[i]-a[i-1]]=i; } while (i<=n){ calc(); } printf("%d\n",ans);}
0 0
- 【BZOJ3100】排列
- [bzoj3100]排列
- 【BZOJ3100】排列【杂项】
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- 排列
- linux基础学习总结03
- ArrayList
- z-wave_device_class_specification中对doorbell门铃实现功能的规定
- c语言==常见问答细节点(19)
- 使用benchmark.js进行前端代码基准测试
- [bzoj3100]排列
- 齐次坐标
- 密码同时包含8~20位数字和大小写字母,不包含特殊字符的判断方法(正则表达式)
- 防止出现乱码,J2EE项目一致使用UTF-8编码设置方法
- 告一段落
- shell 脚本之 curl 请求
- android注解入门 并来自己写一个框架
- RF常用库简介(robotframework)
- Power MTA 配置文件参数配置说明