• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
AC_Artist.zig_zag
然而我依然在补题、
博客园    首页    新随笔    联系   管理    订阅  订阅

bzoj3100 排列

  这个题有点恶心啊,总觉得以前做过,可就是想不出来。最后在发现是meng神出的一次模拟赛题= =当时我还P都不会呢...

  这个题有两个关键点,一个是选取的子序列内不能有重复,二是选取的子序列要是一个排列(当然这包含了一)。首先如果确定了不会重复,那么只要子序列内的数的和等于(len+1)*len/2就行了,那么怎么确定不重复呢?

  我们可以O(N)时间求出来每个数两边第一个和它相同的数的位置(L,R),这样我们可以不断地更新合法的序列的范围。

  具体方案:我们先确定每一个1的位置(因为每个区间首先必须有1),按照这个来划分区间。我们先从左到右扫每个区间,相当于枚举了右端点k(我们要包含那个1),同时记录最大值mx,作为更新答案的标准(因为最大值同时是排列的长度)。然后我们只要保证左端点是合法的就行了。我们不断地用每个数的L来更新左边界(左端点的最小值),这样只要保证k-mx+1在大于左边界就行了,再用前缀和判定是不是排列就行了。

  这个题被空间卡的好惨,贴一个没优化空间的代码吧。

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #define maxn 1200000
 7 using namespace std;
 8 int l[maxn],r[maxn],s[maxn],a[maxn],last[maxn],st[maxn];
 9 int n,m;
10 
11 int main()
12 {
13     //freopen("perm.in","r",stdin);
14     scanf("%d",&n);
15     for (int i=1;i<=n;i++) 
16     {
17         scanf("%d",&a[i]);
18         s[i]=s[i-1]+a[i];
19         if (a[i]==1) st[++m]=i;
20     }
21     st[0]=0,st[m+1]=n+1;
22     for (int i=1;i<=n;i++) 
23     {
24         l[i]=last[a[i]];
25         last[a[i]]=i;
26     }
27     for (int i=1;i<=n;i++) last[i]=n+1;
28     for (int i=n;i;i--)
29     {
30         r[i]=last[a[i]];
31         last[a[i]]=i;
32     }
33     int ans=0;
34     for (int i=1;i<=m;i++)
35     {
36         int j=st[i];//枚举1
37         int mx=0,rr=n+1;
38         for (int k=j;k>=st[i-1]+1;k--)//向左扫,确定左端点
39         {
40             mx=max(mx,a[k]);//区间中最大值(同时也是答案长度)
41             rr=min(rr,r[k]-1);//区间右端点最大值
42             if (k+mx-1<=rr&&s[k+mx-1]-s[k-1]==(mx+1)*mx/2) ans=max(ans,mx);
43         }
44     }
45     for (int i=m;i;i--)
46     {
47         int j=st[i];//枚举1
48         int mx=0,ll=0;
49         for (int k=j;k<=st[i+1]-1;k++)//向右扫,确定右端点
50         {
51             mx=max(mx,a[k]);//区间中最大值(同时也是答案长度)
52             ll=max(ll,l[k]+1);//区间中左端点最大值
53             if (k-mx+1>=ll&&s[k]-s[k-mx]==(mx+1)*mx/2) ans=max(ans,mx);
54         }
55     }
56     printf("%d\n",ans);
57     return 0;
58 }
P

 

AC without art, no better than WA !
posted @ 2013-05-16 20:07  Zig_zag  阅读(805)  评论(1)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3