luogu P2336 [SCOI2012]喵星球上的点名

传送门

这题tm把AC自动机叉掉了,,,

只能考虑别的做法

把所有串连在一起,不同串的交界处加入一些不同的字符,然后求出sa数组和height数组,现在一个询问的答案就是和那个询问串的lcp正好为询问串长度的原串个数,而这在把后缀排好序后是一个区间,每个原串答案为包含这个原串的某个点的区间个数

如果将每个原串的点染成对应编号的颜色,那么现在求的是每个区间包含的点的颜色种类和每种点被多少个区间包含,可以用莫队实现,前者就是HH的项链,后者可以在每种颜色对第一种答案加上贡献时对其答案加上剩余询问个数,在对第一种答案减去贡献时对其答案减去剩余询问个数

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double

using namespace std;
const int N=400000+10,M=100000+10;
il int rd()
{
  int x=0,w=1;char ch=0;
  while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
  return x*w;
}
int n,l1,l2,m=10000;
int rk[N],sa[N],wr[N],bk[N],wx[N],he[N];
int cc[N];
il bool cmp(int a,int b,int j){return wr[a]==wr[b]&&wr[a+j]==wr[b+j];}
il void gSA(int m)
{
  for(int i=1;i<=n;++i) ++bk[rk[i]=cc[i]];
  for(int i=1;i<=m;++i) bk[i]+=bk[i-1];
  for(int i=n;i;--i) sa[bk[rk[i]]--]=i;
  int tp,j=1,p=0;
  while(p<n)
    {
      tp=0;
      for(int i=n-j+1;i<=n;++i) wx[++tp]=i;
      for(int i=1;i<=n;++i) if(sa[i]>j) wx[++tp]=sa[i]-j;
      for(int i=1;i<=n;++i) wr[i]=rk[wx[i]];
      for(int i=0;i<=m;++i) bk[i]=0;
      for(int i=1;i<=n;++i) ++bk[wr[i]];
      for(int i=1;i<=m;++i) bk[i]+=bk[i-1];
      for(int i=n;i;--i) sa[bk[wr[i]]--]=wx[i];
      for(int i=1;i<=n;++i) wr[i]=rk[i];
      rk[sa[1]]=p=1;
      for(int i=2;i<=n;++i) rk[sa[i]]=p+=(cmp(sa[i],sa[i-1],j)^1);
      m=p,j<<=1;
    }
  for(int i=1,j;i<=n;++i)
    {
      he[rk[i]]=he[rk[i-1]]?he[rk[i-1]]-1:0;
      j=sa[rk[i]-1];
      while(cc[i+he[rk[i]]]==cc[j+he[rk[i]]]) ++he[rk[i]];
    }
}
int p[M][2],w[M],len[M],be[N],b2[N],cn[M],na,a1[M],a2[M];
il void ad(int x,int res)
{
  ++cn[b2[sa[x]]];
  if(b2[sa[x]]&&cn[b2[sa[x]]]==1) ++na,a2[b2[sa[x]]]+=res;
}
il void dl(int x,int res)
{
  --cn[b2[sa[x]]];
  if(b2[sa[x]]&&cn[b2[sa[x]]]==0) --na,a2[b2[sa[x]]]-=res;
}
int mi[N][20],hbt[N];
il int gmin(int l,int r)
{
  if(l>r) swap(l,r);
  ++l;
  if(l>r) return -1;
  int z=hbt[r-l+1];
  return min(mi[l][z],mi[r-(1<<z)+1][z]);
}
struct qu
{
  int l,r,id;
  bool operator < (const qu bb) const {return (be[l]^be[bb.l])?l<bb.l:r<bb.r;}
}qq[M];

int main()
{
  l1=rd(),l2=rd();
  cc[0]=m;
  for(int i=1;i<=l1;++i)
    {
      p[i][0]=n+1;
      int k=rd();
      while(k--) cc[++n]=rd();
      cc[++n]=++m;
      k=rd();
      while(k--) cc[++n]=rd();
      cc[++n]=++m;
      p[i][1]=n-1;
    }
  for(int i=1;i<=l2;++i)
    {
      w[i]=n+1;
      int k=len[i]=rd();
      while(k--) cc[++n]=rd();
      cc[++n]=++m;
    }
  --n;
  gSA(m);
  int sqrtn=sqrt(n),lz=log2(n);
  hbt[0]=-1;
  for(int i=0;i<=n;++i) be[i]=i/sqrtn;
  for(int i=1;i<=n;++i) hbt[i]=hbt[i-1]+((i&(-i))==i);
  for(int i=1;i<=n;++i)
    mi[i][0]=he[i];
  for(int j=1;j<=lz;++j)
    for(int i=1;i<=n-(1<<(j-1));++i)
      mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
  for(int i=1;i<=l2;++i)
    {
      qq[i].l=qq[i].r=rk[w[i]],qq[i].id=i;
      int l=1,r=rk[w[i]]-1;
      while(l<=r)
        {
          int mid=(l+r)>>1;
          if(gmin(mid,rk[w[i]])==len[i]) qq[i].l=mid,r=mid-1;
          else l=mid+1;
        }
      l=rk[w[i]]+1,r=n;
      while(l<=r)
        {
          int mid=(l+r)>>1;
          if(gmin(rk[w[i]],mid)==len[i]) qq[i].r=mid,l=mid+1;
          else r=mid-1;
        }
    }
  sort(qq+1,qq+l2+1);
  for(int i=1,j=1;;++i)
    {
      while(j<=l1&&i>p[j][1]) ++j;
      if(j>l1) break;
      b2[i]=(i>=p[j][0]?j:0);
    }
  for(int i=1,l=1,r=0;i<=l2;++i)
    {
      while(r<qq[i].r) ++r,ad(r,l2-i+1);
      while(r>qq[i].r) dl(r,l2-i+1),--r;
      while(l<qq[i].l) dl(l,l2-i+1),++l;
      while(l>qq[i].l) --l,ad(l,l2-i+1);
      a1[qq[i].id]=na;
    }
  for(int i=1;i<=l2;++i) printf("%d\n",a1[i]);
  for(int i=1;i<=l1;++i) printf("%d ",a2[i]);
  return 0;
}

推荐去dd我的xzz巨佬博客看更优秀的题解

原文地址:https://www.cnblogs.com/smyjr/p/10100311.html

时间: 2024-10-11 01:53:38

luogu P2336 [SCOI2012]喵星球上的点名的相关文章

P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

P2336 [SCOI2012]喵星球上的点名 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define rint register int using namespace std; int read(){ char c=getchar();int x=0; while(

洛谷 P2336 [SCOI2012]喵星球上的点名

题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示.为了方便描述,a180285 决定用数串来表示喵星人的名字. 现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结

BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 805  Solved: 380 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,

BZOJ 2754: [SCOI2012]喵星球上的点名

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1926  Solved: 850[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1359  Solved: 618[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2745 Solved: 1190 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么

[BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示.为了方便描述,a180285决定用数串来表示喵星人的名字. 现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?

[SCOI2012]喵星球上的点名——堪称九种方法做的题

题意: 给你N个串对,M个询问串,对每个询问串求是多少串对的子串(在串对的某一个中作为子串),以及每个串对最终是包含了多少询问串 方法众多.. 可谓字符串家族八仙过海各显神通. 复杂度不尽相同,O(nlogn),O(nsqrt(n)),O(玄学)(也就是暴力) (数据比较水,所以一些暴力就过去了) 做法基本都是离线. 法一:AC自动机+暴力 对询问串建AC自动机,把主串往上跑. 匹配到了一个节点,就暴力跳fail,把沿途的点如果是询问串的结尾,ans++,并打上标记,防止重复计数. 一串1111