DestinHistoire

 

BZOJ-2081 [Poi2010]Beads(hash)

题目描述

  把序列 \(a(1\leq |a|\leq 2\times 10^5)\) 从开头开始切成长度为 \(k\) 的若干子串(若最后一段子串的长度小于 \(k\) 则舍弃),选择一个最合适的 \(k\) 值,使不同子串的数量尽可能多(子串可以翻转)。输出最多不同子串的个数,能获得最大值的 \(k\) 的个数。

分析

  直接枚举 \(k\) 的大小,同时计算序列后缀的 \(\text{hash}\) 值,暴力判断即可,时间复杂度 \(O(n+\frac{n}{2}+\frac{n}{3}+\cdots+1)\approx O(n\log n)\)。由于不同的 \(\text{hash}\) 值需要用 set 存,所以时间复杂度会再带一个 \(\log\),即 \(O(n\log^2 n)\)。在判断某个子串是否是另一个子串的翻转时,可以把前缀 \(\text{hash}\) 值和后缀 \(\text{hash}\) 值的较小值插入到 set 中,即可达到去重的效果。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
const int BASE1=131;
const int BASE2=139;
int n,a[N+10],temp[N+10];
unsigned long long pow1[N+10],pow2[N+10];
unsigned long long hash1[N+10],hash2[N+10];
unsigned long long __hash1[N+10],__hash2[N+10];
unsigned long long get1(int op,int l,int r)
{
    if(op==1)
        return hash1[r]-hash1[l-1]*pow1[r-l+1];
    if(op==2)
        return hash2[r]-hash2[l-1]*pow2[r-l+1];
}
unsigned long long get2(int op,int l,int r)
{
    if(op==1)
        return __hash1[l]-__hash1[r+1]*pow1[r-l+1];
    if(op==2)
        return __hash2[l]-__hash2[r+1]*pow2[r-l+1];
}
set<pair<unsigned long long,unsigned long long> > st;
int num(int len)
{
    st.clear();
    for(int l=1;l+len-1<=n;l=l+len)
    {
        int r=l+len-1;
        unsigned long long X1=get1(1,l,r),X2=get1(2,l,r);
        unsigned long long Y1=get2(1,l,r),Y2=get2(2,l,r);
        st.insert(make_pair(min(X1,Y1),min(X2,Y2)));
    }
    int sz=st.size();
    return sz;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    pow1[0]=pow2[0]=1;
    for(int i=1;i<=n;i++)
    {
        pow1[i]=pow1[i-1]*BASE1;
        pow2[i]=pow2[i-1]*BASE2;
    }
    for(int i=1;i<=n;i++)
    {
        hash1[i]=hash1[i-1]*BASE1+a[i];
        hash2[i]=hash2[i-1]*BASE2+a[i];
    }
    for(int i=n;i>=1;i--)
    {
        __hash1[i]=__hash1[i+1]*BASE1+a[i];
        __hash2[i]=__hash2[i+1]*BASE2+a[i];
    }
    int maxn=-1,cnt=0;
    for(int i=1;i<=n;i++)
    {
        int ans=num(i);
        if(ans>maxn)
        {
            maxn=ans;
            cnt=0;
        }
        if(ans==maxn)
            temp[++cnt]=i;
    }
    cout<<maxn<<" "<<cnt<<endl;
    for(int i=1;i<=cnt;i++)
        printf("%d ",temp[i]);
    puts("");
    return 0;
}

posted on 2020-11-18 20:53  DestinHistoire  阅读(107)  评论(0)    收藏  举报

导航