用后缀树统计出出现了x次的本质不同的子串的个数,最后再乘以x,得到一个多项式。

这个多项式常数项为0,但是一次项不为0。

于是把整个多项式除以一次项,通过多项式求ln和多项式求exp求出它的幂。

最后再把除掉的项乘回来即可,时间复杂度$O(n\log n)$。

  1. #include<cstdio>
  2. #include<cstring>
  3. typedef long long ll;
  4. const int N=262144,K=17,inf=~0U>>2,S=27,M=200010,P=1005060097,G=5;
  5. char s[M];
  6. int n,m,x,i,j,k,C;
  7. int a[N+10],b[N+10],tmp[N],tmp2[N],g[K+1],ng[K+1],inv[N+10],inv2;
  8. int text[M],root,last,pos,need,remain,acnode,ace,aclen,size[M];
  9. inline int min(int a,int b){return a<b?a:b;}
  10. struct node{int st,en,lk,son[S];inline int len(){return min(en,pos+1)-st;}}tree[M];
  11. inline int new_node(int st,int en=inf){return tree[++last].st=st,tree[last].en=en,last;}
  12. inline int acedge(){return text[ace];}
  13. inline void addedge(int node){
  14. if(need)tree[need].lk=node;
  15. need=node;
  16. }
  17. inline bool down(int node){
  18. if(aclen>=tree[node].len())return ace+=tree[node].len(),aclen-=tree[node].len(),acnode=node,1;
  19. return 0;
  20. }
  21. inline void init(){
  22. need=last=remain=ace=aclen=0;
  23. root=acnode=new_node(pos=-1,-1);
  24. }
  25. inline void extend(int c){
  26. text[++pos]=c;need=0;remain++;
  27. while(remain){
  28. if(!aclen)ace=pos;
  29. if(!tree[acnode].son[acedge()])tree[acnode].son[acedge()]=new_node(pos),addedge(acnode);
  30. else{
  31. int nxt=tree[acnode].son[acedge()];
  32. if(down(nxt))continue;
  33. if(text[tree[nxt].st+aclen]==c){aclen++;addedge(acnode);break;}
  34. int split=new_node(tree[nxt].st,tree[nxt].st+aclen);
  35. tree[acnode].son[acedge()]=split;
  36. tree[split].son[c]=new_node(pos);
  37. tree[nxt].st+=aclen;
  38. tree[split].son[text[tree[nxt].st]]=nxt;
  39. addedge(split);
  40. }
  41. remain--;
  42. if(acnode==root&&aclen)aclen--,ace=pos-remain+1;
  43. else acnode=tree[acnode].lk?tree[acnode].lk:root;
  44. }
  45. }
  46. void dfs(int x,int sum){
  47. sum+=tree[x].len();
  48. if(tree[x].en==inf&&pos-sum+1<=n)size[x]=1;
  49. for(int i=0;i<S;i++)if(tree[x].son[i]){
  50. int j=tree[x].son[i];
  51. dfs(j,sum),size[x]+=size[j];
  52. }
  53. if(size[x])a[size[x]]=(a[size[x]]+tree[x].len())%P;
  54. }
  55. inline int pow(int a,int b){int t=1;for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;return t;}
  56. inline void NTT(int*a,int n,int t){
  57. for(int i=1,j=0;i<n-1;i++){
  58. for(int s=n;j^=s>>=1,~j&s;);
  59. if(i<j){int k=a[i];a[i]=a[j];a[j]=k;}
  60. }
  61. for(int d=0;(1<<d)<n;d++){
  62. int m=1<<d,m2=m<<1,_w=t==1?g[d]:ng[d];
  63. for(int i=0;i<n;i+=m2)for(int w=1,j=0;j<m;j++){
  64. int&A=a[i+j+m],&B=a[i+j],t=1LL*w*A%P;
  65. A=B-t;if(A<0)A+=P;
  66. B=B+t;if(B>=P)B-=P;
  67. w=1LL*w*_w%P;
  68. }
  69. }
  70. if(t==-1)for(int i=0,j=inv[n];i<n;i++)a[i]=1LL*a[i]*j%P;
  71. }
  72. void getinv(int*a,int*b,int n){
  73. if(n==1){b[0]=pow(a[0],P-2);return;}
  74. getinv(a,b,n>>1);
  75. int k=n<<1,i;
  76. for(i=0;i<n;i++)tmp[i]=a[i];
  77. for(i=n;i<k;i++)tmp[i]=b[i]=0;
  78. NTT(tmp,k,1),NTT(b,k,1);
  79. for(i=0;i<k;i++){
  80. b[i]=(ll)b[i]*(2-(ll)tmp[i]*b[i]%P)%P;
  81. if(b[i]<0)b[i]+=P;
  82. }
  83. NTT(b,k,-1);
  84. for(i=n;i<k;i++)b[i]=0;
  85. }
  86. inline void getln(int*a,int*b,int n){
  87. getinv(a,tmp2,n);
  88. int k=n<<1,i;
  89. for(i=0;i<n-1;i++)b[i]=(ll)a[i+1]*(i+1)%P;
  90. for(i=n-1;i<k;i++)b[i]=0;
  91. NTT(b,k,1),NTT(tmp2,k,1);
  92. for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp2[i]%P;
  93. NTT(b,k,-1);
  94. for(i=n-1;i;i--)b[i]=(ll)b[i-1]*inv[i]%P;b[0]=0;
  95. }
  96. void getexp(int*a,int*b,int n){
  97. if(n==1){b[0]=1;return;}
  98. getexp(a,b,n>>1);
  99. getln(b,tmp,n);
  100. int k=n<<1,i;
  101. for(i=0;i<n;i++){tmp[i]=a[i]-tmp[i];if(tmp[i]<0)tmp[i]+=P;}
  102. if((++tmp[0])==P)tmp[0]=0;
  103. for(i=n;i<k;i++)tmp[i]=b[i]=0;
  104. NTT(tmp,k,1),NTT(b,k,1);
  105. for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp[i]%P;
  106. NTT(b,k,-1);
  107. for(i=n;i<k;i++)b[i]=0;
  108. }
  109. int main(){
  110. scanf("%d%d%s",&m,&x,s+1);
  111. if(m>x)return puts("0"),0;
  112. n=std::strlen(s+1);
  113. for(i=1;i<=n;extend(s[i++]-'a'));extend(26);
  114. pos--,dfs(root,0);
  115. for(i=0;i<=x;i++)a[i]=1LL*a[i]*i%P;
  116. C=a[1],j=pow(C,P-2);
  117. for(i=0;i<x;i++)a[i]=1LL*a[i+1]*j%P;
  118. for(i=x;i<k;i++)a[i]=0;
  119. for(g[K]=pow(G,(P-1)/N),ng[K]=pow(g[K],P-2),i=K-1;~i;i--)g[i]=(ll)g[i+1]*g[i+1]%P,ng[i]=(ll)ng[i+1]*ng[i+1]%P;
  120. for(inv[1]=1,i=2;i<=N;i++)inv[i]=(ll)(P-inv[P%i])*(P/i)%P;inv2=inv[2];
  121. for(k=1;k<=x;k<<=1);
  122. getln(a,b,k);
  123. for(i=0;i<k;i++)b[i]=1LL*b[i]*m%P;
  124. getexp(b,a,k);
  125. return printf("%d",1LL*a[x-m]*pow(C,m)%P),0;
  126. }

  

BZOJ4175 : 小G的电话本的更多相关文章

  1. BZOJ 4175: 小G的电话本 SAM+FFT

    4175: 小G的电话本 Time Limit: 45 Sec  Memory Limit: 256 MBSubmit: 195  Solved: 48[Submit][Status][Discuss ...

  2. BZOJ 4175 小G的电话本 ——NTT

    后缀自动机统计出现了各种次数的串的和. 就是所谓的生成函数 然后FFT卷积即可. 卷积快速幂$n\log n \log n$ 注意一下实现,可以少两次NTT #include <map> ...

  3. C语言实现电话本 动态开辟 信息存储于文件

    下面是我用C写的一个电话本小项目,实现的功能有:添加 删除 修改 查找 排序 清空 显示,功能还是比较全的,内存也是动态开辟的.能存储于本地,能从本地读出并显示 头文件部分代码,contact.h: ...

  4. 微信电话本可免费拨打网络电话 通话一分钟约300K流量

    微信电话本新版本于昨日晚间发布,这是一款智能通讯增强软件,通话双方都下载此APP并开通免费通话功能就能使用微信电话本拨打免费网络电话,在对方无法接通情况下还能将音频转向语音信箱,微信电话本目前支持An ...

  5. C++之路进阶——codevs2933(诗人小G)

    2933 诗人小G 2009年NOI全国竞赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master     题目描述 Description 小G是一个出色的诗人 ...

  6. 苹果IPhone手机由于更新了IOS7 Beta测试版导致“激活出错”后,如何还原电话本和照片方法

    苹果这狗日的,手段果然狠,因为用户提前升级了测试版又没有更新正式版,就突然把手机变砖头,既不让升级正式版,也不让备份手机中的信息,确实有必要这样吗? 我的手机是IPone4s,在看了6月Apple W ...

  7. Android-->发送短信页面实现(短信发送以及群发和从电话本中选择联系人)-----------》2

    分析下怎么写 首先,我们需要一个输入框,可以手动的输入手机号码, 其次,很少有人愿意手动输入,那么我们需要提供一个按钮来给我们的用户选择自己电话本中的联系人(一次可以选择多个即群发) 然后,我们需要一 ...

  8. jdbc电话本项目

    整体思路:在登陆之后才能查看自己的电话本,电话本中包含用户名,联系人名字,电话,性别,分类: 1.登陆注册页面--数据库User表,注册登陆使用 2.电话本的前段显示,用表格和表单, 3.创建存取的电 ...

  9. JavaWeb项目之电话本,两个版本,以及总结反思

    使用技术: Oracle 数据库 前端后台: Servlet + jsp + JDBC + html + css + js 前端界面自定, 但一定实现需要的功能 实现功能: 用户可以登录 登录之后可以 ...

随机推荐

  1. python---django中form组件(数据添加前使用自定义方法<django预留扩展点3个>进行验证,以及源码分析)

    form组件代码: from app02.models import Userfrom django.core.exceptions import ValidationError class Ajax ...

  2. 基于JWT(Json Web Token)的ASP.NET Web API授权方式

    token应用流程 初次登录:用户初次登录,输入用户名密码 密码验证:服务器从数据库取出用户名和密码进行验证 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT 返还JWT ...

  3. 使用渐进式JPEG来提升用户体验

    今天才认识到原来JPEG文件有两种保存方式他们分别是Baseline JPEG(标准型)和Progressive JPEG(渐进式).两种格式有相同尺寸以及图像数据,他们的扩展名也是相同的,唯一的区别 ...

  4. Asp.Net中索引器的用法

    索引器定义类似于属性,但其功能与属性并不相同.索引器提供一种特殊的方法编写get和set访问器.属性可以像访问字段一样访问对象的数据,索引器可以使用户像访问数组一样访问类成员. 一.索引器特性 1.g ...

  5. 新建 Spring Mvc Web + Maven 的 maven 错误 (二)

    新建项目后,可能由于哪边配置不正确,或也可能是编码问题,就有可能在创建初始就可能发生错误: 这是 pom.xml 中提示的错误,有的人说要删除 maven 的本地仓库位置:c:\用户[Users]\A ...

  6. HTML5 移动开发(CSS3设计移动页面样式)

    1.如何创建CSS样式表 2.CSS3的卓越特性 3.基于设备属性改变样式的媒体查询 4.如何使用属性改变元标签创建更美观移动页面   层叠样式表是移动WEB开发中的一个重要组成部分,本次分享将学到如 ...

  7. if语句引起的bug

    最近维护高手留下的api项目,客户端反馈一个bug过来,然后查找到可能出错的代码位置,是一个if语句,乍一看好像没什么问题,代码如下: if (company.UserId != userId || ...

  8. Kth Smallest Number in Sorted Matrix

    Find the kth smallest number in at row and column sorted matrix. Example Given k = 4 and a matrix: [ ...

  9. 使用InstallShield打包windriver驱动-转

    转自:http://blog.csdn.net/weixin_29796711/article/details/72822052 用户在使用我们用windriver开发的硬件驱动时,需要先安装wind ...

  10. 6 个 Linux 运维典型问题,大牛的分析解决思路在这里 【转】

    作为一名合格的 Linux 运维工程师,一定要有一套清晰.明确的解决故障思路,当问题出现时,才能迅速定位.解决问题,这里给出一个处理问题的一般思路: 重视报错提示信息:每个错误的出现,都是给出错误提示 ...