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

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)

#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;
}

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/101901028