zoukankan      html  css  js  c++  java
  • 【bzoj1318】[Spoj744] Longest Permutation(乱搞)

      题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1318

      这道题的大意是要求一个长度为len,并包含1~len所有数,并使len最大的子区间。开始看题的时候一脸懵逼(好像可以二分?),然后写到一半突然发现二分有反例。

      于是上网搜了一波题解。

      正确解法:

      我们可以发现这个区间必定满足这样的性质:假设它的长度为len,则区间内最大值为len,区间内所有数的和为(len+1)*len/2,并且区间内所有数两两不相等。

      因为区间内一定包含1,所以我们可以以1为界点划分整个序列。然后我们假设区间内的最大值在1的左侧,于是从当前的1开始向左枚举,并把从当前枚举到的数到1之间的最大值作为区间的长度,然后用上面的法则判断该区间是否合法。因为求区间和明显比区间最大值方便,所以我们就用前缀和求出当前区间的和来判断。判断区间里是否有相同的数,只需维护一个nxt数组,每个数右边第一个相同的数出现的位置,然后一边枚举一边更新合法区间的右端点(即与区间内的数有冲突的最左边一个数)。

      代码:

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<map>
    #define ll long long
    #define ull unsigned long long
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define lowbit(x) (x& -x)
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define eps 1e-18
    #define maxn 1000020
    inline ll read(){ll tmp=0; char c=getchar(),f=1; for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=getchar())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f;}
    inline ll power(ll a,ll b){ll ans=0; for(;b;b>>=1){if(b&1)ans=ans*a%mod; a=a*a%mod;} return ans;}
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    using namespace std;
    int a[maxn],nxt[maxn];
    int last[maxn];
    ll sum[maxn];
    int n;
    int work(int n)
    {
        memset(last,0,sizeof(last));
        memset(nxt,0,sizeof(nxt));
        for(int i=1;i<=n;i++){
            sum[i]=sum[i-1]+a[i];
            if(last[a[i]])nxt[last[a[i]]]=i;
            last[a[i]]=i;
        }
        for(int i=1;i<=n;i++)if(!nxt[i])nxt[i]=n+1;
        int ans=0;
        for(int i=1;i<=n;i++)
            if(a[i]==1){
                ans=max(ans,1);
                if(i==1)continue;
                int r=nxt[i],mx=1;
                for(int j=i-1;j>0&&a[j]!=1;j--){
                    r=min(r,nxt[j]); mx=max(mx,a[j]);
                    if(j+mx<=r&&sum[j+mx-1]-sum[j-1]==1ll*(mx+1)*mx/2)ans=max(ans,mx);
                }
            }
        return ans;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        int ans1=work(n);
        for(int i=1;i*2<=n;i++){
            int tmp=a[i]; a[i]=a[n-i+1]; a[n-i+1]=tmp;
        }
        int ans2=work(n);
        printf("%d
    ",max(ans1,ans2));
        return 0;
    }
    bzoj1318
  • 相关阅读:
    Protocol Buffer技术详解(语言规范)
    google protobuf 简单实例
    advStringGrid单元格文字垂直居中
    java中两个字符串如何比较大小
    List集合去除重复对象及equals()、hashCode()方法的作用
    Delphi中使用ActiveX的一些心得
    java List去重方式及效率对比
    Visual Studio Code 调整字体大小
    用最简单的例子实现jQuery图片即时上传
    Linux下绝对经典的命令
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/9164605.html
Copyright © 2011-2022 走看看