[HDU5659]knight
来源:互联网 发布:linux测试网速的命令 编辑:程序博客网 时间:2024/06/07 16:20
题目大意
求一个字符串,从每一个位置分成两部分(当做两个字符串),求本质不同子串数量。
SAM
我们先有一个简单的思路。f[i]表示从i分成两部分的答案。
正难则反,求出原串本质不同子串数量,对于每个位置减去跨线且没在两边出现过的即可。
对于一个子串,如果其出现在原串中最大的右端点为mx,最小的右端点为mi,其长度为len。
如果mx-len>=mi,则因为其所有出现区间交为空,无论从哪个位置分开这个子串都会出现在其中一边。
如果
然而子串个数很多,怎么办呢?
考虑SAM,那么公用right集合的点被缩为一个点,枚举自动机上每个点,然后得到mx和mi(这里说一下mx和mi的求法,因为后缀自动机上一点的right集合是其parent树中子树的right集合的并,因此其mx等于其子树中mx的最大值,mi等于其子树中mi的最小值),同时要得到len的范围[l,r](后缀自动机上一个点的maxs就是step,mins就是其parent树父亲的maxs+1)
那么f的[mx-r+1,mx-l+1]是第一个+1,第二个+2,第三个+3……一直这样下去,然后f的[mx-l+2,mi-1]+r-l+1。
我们考虑线性做,可以设gi=fi-fi-1,那么区间加等差变成了区间+1,后面的平板只需要单点修改。区间加1可以通过开头挂+1结尾挂-1最后线性扫实现。
#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=500000+10,mo=1000000007;int g[maxn*2][10],pre[maxn*2],step[maxn*2],mi[maxn*2],ma[maxn*2],mins[maxn*2],maxs[maxn*2],cnt[maxn*2],ad[maxn],f[maxn];int a[maxn*2];int i,j,k,l,r,t,n,m,tot,last,sum,ans;char ch;char get(){ char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); return ch;}void add(int x){ int np=++tot,p=last; mi[tot]=100000000; step[np]=step[p]+1; while (p>=0&&g[p][x]==0){ g[p][x]=np; p=pre[p]; } if (p==-1) pre[np]=0; else{ int q=g[p][x]; if (step[q]==step[p]+1) pre[np]=q; else{ int nq=++tot,i; mi[tot]=100000000; fo(i,0,9) g[nq][i]=g[q][i]; pre[nq]=pre[q]; pre[q]=nq; step[nq]=step[p]+1; pre[np]=nq; while (p>=0&&g[p][x]==q){ g[p][x]=nq; p=pre[p]; } } } last=np;}int quicksortmi(int x,int y){ if (!y) return 1; int t=quicksortmi(x,y/2); t=(ll)t*t%mo; if (y%2) t=(ll)t*x%mo; return t;}int main(){ freopen("knight6.in","r",stdin); scanf("%d",&n); pre[0]=-1; fo(i,1,n){ ch=get(); add(ch-'0'); ma[last]=mi[last]=i; } fo(i,1,tot) sum=(sum+step[i]-step[pre[i]])%mo; /*fd(i,tot,1){ mi[pre[i]]=min(mi[pre[i]],mi[i]); ma[pre[i]]=max(ma[pre[i]],ma[i]); maxs[i]=step[i]; mins[i]=step[pre[i]]+1; }*/ fo(i,0,tot) cnt[step[i]]++; fo(i,0,step[last]) cnt[i]+=cnt[i-1]; fo(i,0,tot) a[cnt[step[i]]--]=i; fd(i,tot+1,1){ mi[pre[a[i]]]=min(mi[pre[a[i]]],mi[a[i]]); ma[pre[a[i]]]=max(ma[pre[a[i]]],ma[a[i]]); maxs[a[i]]=step[a[i]]; mins[a[i]]=step[pre[a[i]]]+1; } fo(i,1,tot){ l=mins[i];r=maxs[i]; l=max(l,ma[i]-mi[i]+1); if (l>r) continue; ad[ma[i]-r+1]++; ad[ma[i]-l+2]--; f[mi[i]]-=(r-l+1); } k=0; fo(i,1,n){ k=(k+ad[i])%mo; f[i]=(f[i]+k); } fo(i,1,n) f[i]=(f[i]+f[i-1])%mo; fo(i,1,n) f[i]=sum-f[i]; fo(i,1,n-1) ans=(ans+(ll)f[i]*quicksortmi(100013,n-i-1)%mo)%mo; (ans+=mo)%=mo; printf("%d\n",ans);}
0 0
- [HDU5659]knight
- [HDU5659]CA Loves Substring/[JZOJ4705]knight
- hdu5659 CA Loves Substring
- Knight说辞
- Knight Moves
- Sicily1781. Knight
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- Knight Moves
- elasticsearch学习笔记(二)
- Android ViewPager实现引导页
- MySQL Server优化
- 牢记25个最佳的SSH命令
- 不能被工程师群殴(一)
- [HDU5659]knight
- [线段树]hdu1698 Just a Hook(区间更新、延迟标记
- OAuth2授权(Client Credentials)
- HDU 1872 稳定排序
- 实施数据库审计-DBA负责的安全和审计工作以及标准数据库审计
- 对比objdump和readelf
- Oracle简单入门(连载)(1)
- Q1.Two Sum
- 进程和线程关系及区别