2019牛客国庆集训派对day1 C Distinct Substrings —— 二分+哈希

27 篇文章 1 订阅
20 篇文章 0 订阅

This way

题意:

给你一个串s,定义f(s)为这个字符串不同子串的数量,h©为f(s+c)-f(s)。问你
在这里插入图片描述

题解:

正解好像是扩展KMP,but二分+哈希也能过,就是要调一下哈希的值,23,29,31,101,131,这些我都过不去,最后自暴自弃试了一下1e9+7,它居然就过了,过了。。
首先我们存下所有值出现的位置,由于这里没办法开1e6个vector,那么我们就模拟一个链表,ne[i]表示i这个位置指向的下一个位置,top[i]表示值为i的时候出现的最后一个位置在哪,只要我们循环使用ne数组,就可以实现访问同一个值的每个位置。因为每个值只会被访问一次,所以最坏情况每个位置会被访问一次,加上二分的话,每个位置会被访问log次,也就是nlogn的时间复杂度。
那么对于每个c,我们二分它在前面出现的最长长度,然后按照ne数组去check一遍即可。总时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
好像被卡内存了…那么我们改一下快读缓冲区大小,然后不用unsigned long long ,改用unsigned int ,并且使用双哈希,最后将Pow数组改成快速幂,空间换时间,最终卡了过去。
新的代码在下面

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
#pragma GCC optimize(2)
#define ri register int
#define ll long long
#define ull unsigned long long
inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  if(c==EOF){
      x=-1;
      return ;
  }
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}


const ll mod=1e9+7;
const int N=1e6+5;
int s[N];
ull p[N],h[N];
int Pow[N];
ull get_h(int l,int r)
{
    return h[r]-p[r-l+1]*h[l-1];
}
int ne[N],top[N],n,m;
bool check(int l,int x)
{
    int now=top[x];
    while(now&&now>=l)
    {
        ull h1=get_h(n+1-l+1,n+1);
        ull h2=get_h(now-l+1,now);
        if(h1==h2)
            return 1;
        now=ne[now];
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    p[0]=Pow[0]=1;
    for(int i=1;i<N;i++)
        p[i]=p[i-1]*mod,Pow[i]=1ll*Pow[i-1]*3ll%mod;

    while(read(n),n!=EOF)
    {
        read(m);
        for(int i=1;i<=m;i++)top[i]=0;
        for(int i=1;i<=n;i++)
        {
            read(s[i]);
            ne[i]=top[s[i]],top[s[i]]=i;
        }
        for(int i=1;i<=n;i++)
            h[i]=h[i-1]*mod+(ll)s[i]+80ll;
        ll ans=0;
        for(ll i=1;i<=m;i++)
        {
            h[n+1]=h[n]*mod+i+80ll;
            if(!top[i])
                ans=ans^(1ll*Pow[i]*(n+1)%mod);
            else
            {
                int l=1,r=n,mid,a;
                while(r>=l)
                {
                    mid=l+r>>1;
                    if(check(mid,i))
                        l=mid+1,a=mid;
                    else
                        r=mid-1;
                }
                ans=ans^(1ll*Pow[i]*(n+1-a)%mod);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
#pragma GCC optimize(2)
#define ri register int
#define ll long long
#define ull unsigned long long
#define ui unsigned int
#define pa pair<ui,ui>
inline char nc(){
  static char buf[1000005],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,1000005,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  if(c==EOF){
      x=-1;
      return ;
  }
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}


const pa mod={13331,31};
const int N=1e6+5;
int s[N];
pa p[N],h[N];
const ll mm=1e9+7;
ll qpow(ll a,ll b){ll ans=1;for(;b;b>>=1,a=a*a%mm)if(b&1)ans=ans*a%mm;return ans;}
pa get_h(int l,int r)
{
    return (pa){h[r].first-p[r-l+1].first*h[l-1].first,h[r].second-p[r-l+1].second*h[l-1].second};
}
int ne[N],top[N],n,m;
bool check(int l,int x)
{
    int now=top[x];
    while(now&&now>=l)
    {
        pa h1=get_h(n+1-l+1,n+1);
        pa h2=get_h(now-l+1,now);
        if(h1.first==h2.first&&h1.second==h2.second)
            return 1;
        now=ne[now];
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    p[0]={1,1};
    for(int i=1;i<N;i++)
        p[i]={p[i-1].first*mod.first,p[i-1].second*mod.second};

    while(read(n),n!=EOF)
    {
        read(m);
        for(int i=1;i<=m;i++)top[i]=0;
        for(int i=1;i<=n;i++)
        {
            read(s[i]);
            ne[i]=top[s[i]],top[s[i]]=i;
        }
        for(int i=1;i<=n;i++)
            h[i]={h[i-1].first*mod.first+(ll)s[i]+80ll,h[i-1].second*mod.second+(ll)s[i]+80ll};
        ll ans=0;
        for(ll i=1;i<=m;i++)
        {
            h[n+1]={h[n].first*mod.first+i+80ll,h[n].second*mod.second+i+80ll};
            if(!top[i])
                ans=ans^(qpow(3,i)*(n+1)%mm);
            else
            {
                int l=1,r=n,mid,a;
                while(r>=l)
                {
                    mid=l+r>>1;
                    if(check(mid,i))
                        l=mid+1,a=mid;
                    else
                        r=mid-1;
                }
                ans=ans^(1ll*qpow(3,i)*(n+1-a)%mm);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值