BZOJ2081: [Poi2010]Beads 哈希

题目大意:给出一个串,求按每几个一组的分割方式可以得到最多的不同子串。正序倒序算一种,末尾有剩余的不算。长度<=2e5
直接枚举每种分割方案,子串(l,r)的哈希值就是(hash[r]-hash[l-1]*x^(r-l+1))mod p,正着反着都要做,然后再对产生的哈希值做个哈希判重,总复杂度nlogn。
据说这题直接自然溢出就能过,我到底为什么写了个双取模而且还非要用pbds哈希表。。。时限10秒跑了9.388秒,差点就卡不过去了23333

#include<cstdio>
#include<ext/pb_ds/assoc_container.hpp>
#define gm 200005
#ifdef ONLINE_JUDGE
#define null_type null_mapped_type
#endif
#define pow __pow__
using namespace __gnu_pbds;
typedef long long ll;
size_t n;
ll a[gm];
struct pair
{
    ll a,b;
    pair(const ll &a=0,const ll &b=0):a(a),b(b){}
    inline pair operator + (const ll &y) const
    {return pair(a+y,b+y);}
    inline pair operator + (const pair &y) const
    {return pair(a+y.a,b+y.b);}
    inline pair operator - (const pair &y) const
    {return pair(a-y.a,b-y.b);}
    inline pair operator * (const ll &y) const
    {return pair(a*y,b*y);}
    inline pair operator * (const pair &y) const
    {return pair(a*y.a,b*y.b);}
    inline pair operator % (const pair &y) const
    {return pair(a%y.a,b%y.b);}
    inline bool operator == (const pair &y) const
    {return a==y.a&&b==y.b;}
}z[gm],f[gm],pow[gm];
struct func
{
    inline size_t operator () (const pair &x) const
    {
        static std::tr1::hash<ll> h;
        return h(ll(h(x.a))<<32|h(x.b));
    }
};
const pair m(10000019ll,10000079ll);
int maxn=0;
int ks[gm],top;
inline pair getz(int fr,int ta)
{
    pair p=z[ta]-z[fr-1]*pow[ta-fr+1];
    return (p%m+m)%m;
}
inline pair getf(int fr,int ta)
{
    pair p=f[fr]-f[ta+1]*pow[ta-fr+1];
    return (p%m+m)%m;
}
inline size_t count(int x)
{
    static gp_hash_table<pair,null_type,func> tb;
    tb.clear();
    pair p,q;
    size_t res=0;
    for(int i=x;i<=n;i+=x)
    {
        p=getz(i-x+1,i);
        q=getf(i-x+1,i);
        if(tb.find(p)==tb.end()&&tb.find(q)==tb.end())
        tb.insert(p),tb.insert(q),++res;
    }
    return res;
}
int main()
{
    pow[0]=pair(1,1);
    scanf("%u",&n);
    for(size_t i=1;i<=n;++i)
    {
        scanf("%lld",a+i);
        z[i]=(z[i-1]*1313131+a[i])%m;
    }
    for(size_t i=n;i;--i)
    f[i]=(f[i+1]*1313131+a[i])%m;
    for(size_t i=1;i<=n;++i)
    {
        pow[i]=(pow[i-1]*1313131)%m;
        size_t cnt=count(i);
        if(cnt>maxn)
        {
            maxn=cnt;
            ks[top=0]=i;
        }
        else if(cnt==maxn)
        ks[++top]=i;
    }
    printf("%d %d\n",maxn,top+1);
    for(int i=0;i<top;++i)
    printf("%d ",ks[i]);
    printf("%d\n",ks[top]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值