[GDKOI2014][JZOJ3572]基因模式
2017-04-16 11:41
281 查看
题目大意
给定一个模板串T,字符集为{A,C,T,G}。有q个询问,每次给出一个串S,字符集也只是上面四个字母,还会给定字符集中某些字母的奇偶性限制,询问S中一共有多少个子串满足以下两个条件:
∙ 这个串是T的一个子串
∙ 对于给定了奇偶性限制的字母,该串中中该字母出现的次数奇偶性要满足这个限制
1≤|T|≤105,∑|S|≤105,q≤103
题目分析
对T串构造后缀自动机,然后拿询问串在上面跑。对于询问串的一个位置i假设我们在SAM上匹配到了节点p,任选rightp中的任意一个节点作为右端点r,可能的答案串左端点在区间[r−matchlen+1,r]内,现在我们要满足奇偶性限制。
既然字符集大小为4,考虑使用4位二进制状态来表示每个字符出现次数的奇偶性,我们处理一下前缀和减一减就可以得到i对答案的贡献。
时间复杂度O(|T|+2|Σ||S|)。
代码实现
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; const int N=100050; const int W=4; const int S=1<<W; const int V=N<<1; int sum [S],pre ; int pur,cor; namespace SAM { struct node { int prt,len,pos; int nxt[W]; }sam[V]; int tot,root; int newnode() { ++tot,memset(sam[tot].nxt,0,sizeof sam[tot].nxt),sam[tot].prt=sam[tot].len=sam[tot].pos=0; return tot; } void init(){tot=0,root=newnode();} int insert(int lst,int c,int ps) { int np=newnode(),p=lst,q; for (sam[np].len=sam[p].len+1,sam[np].pos=ps;p&&!sam[p].nxt[c];p=sam[p].prt) sam[p].nxt[c]=np; if (!p) sam[np].prt=root; else if (sam[q=sam[p].nxt[c]].len==sam[p].len+1) sam[np].prt=q; else { int nq=newnode(); sam[nq]=sam[q],sam[np].prt=sam[q].prt=nq; for (sam[nq].len=sam[p].len+1;p&&sam[p].nxt[c]==q;p=sam[p].prt) sam[p].nxt[c]=nq; } return np; } int match(int &p,int c,int &len) { int ret=0; for (;p&&!sam[p].nxt[c];p=sam[p].prt,len=sam[p].len); p=p?p:root; if (sam[p].nxt[c]) p=sam[p].nxt[c],++len; for (int s=0,r=sam[p].pos,l=r-len;s<S;++s) if (!((s^pur)&cor)) ret+=(r?sum[r-1][pre[r]^s]:(pre[r]^s?0:1))-(l-1>=0?sum[l-1][pre[r]^s]:(pre[r]^s?0:(!l?1:0))); return ret; } }; char T ,str ,L[10]; int id[26]; int n,m,q; int main() { id[0]=0,id[2]=1,id[19]=2,id[6]=3; freopen("pattern.in","r",stdin),freopen("pattern.out","w",stdout); scanf("%d",&q),scanf("%s",T),n=strlen(T),SAM::init(); sum[0][0]=1; for (int i=0,lst=SAM::root;i<n;++i) { lst=SAM::insert(lst,id[T[i]-'A'],i); if (i) for (int s=0;s<S;++s) sum[i][s]=sum[i-1][s]; ++sum[i][pre[i]=(i?pre[i-1]:0)^(1<<id[T[i]-'A'])]; } for (LL ans;q--;printf("%lld\n",ans)) { scanf("%s",str),m=strlen(str); scanf("%s",L),pur=cor=0; for (int i=0;L[i]!='\0';++i) if ('A'<=L[i]&&L[i]<='Z') pur|=1<<id[L[i]-'A'],cor|=1<<id[L[i]-'A']; else cor|=1<<id[L[i]-'a']; ans=0; for (int i=0,lst=SAM::root,l=0;i<m;++i) ans+=SAM::match(lst,id[str[i]-'A'],l); } fclose(stdin),fclose(stdout); return 0; }
相关文章推荐
- GDKOI 2014 基因模式 基于SAM的算法
- GDKOI2014 基因模式
- 【时光回溯】【JZOJ3567】【GDKOI2014】石油储备计划
- 【时光回溯】【JZOJ3571】【GDKOI2014】内存分配
- [jzoj]3555. 【GDKOI2014模拟】树的直径(结论题-树的性质)
- JZOJ B组【GDKOI2014】阶乘
- 【时光回溯】【JZOJ3568】【GDKOI2014】小纪的作业题
- 12.23 jzoj3566. 【GDKOI2014】阶乘
- 【时光回溯】【JZOJ3566】【GDKOI2014】阶乘
- jzoj3555 【GDKOI2014模拟】树的直径 lca+离线
- GDKOI2014 石油储备计划
- [JZOJ]3859. 【NOIP2014八校联考第3场第2试10.5】孤独一生
- 单例模式2014-12
- 如何退出MyEclipse2014的Debug模式
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
- [JZOJ]3858. 【NOIP2014八校联考第3场第2试10.5】挖掘机技术哪家强
- bzoj3572: [Hnoi2014]世界树
- [BZOJ3572][Hnoi2014]世界树 && 虚树+DP
- 【BZOJ3572】【Hnoi2014】世界树 虚树
- bzoj 3572[HNOI2014]世界树