BZOJ 4175: 小G的电话本 SAM+FFT
4175: 小G的电话本
Time Limit: 45 Sec Memory Limit: 256 MB
Submit: 195 Solved: 48
[Submit][Status][Discuss]
Description
小G是一个商人,他有一个电话本。电话本上记下了许多联系人,如timesqr、orzyhb等等。不过Tony对其中的某个联系人的名字S特别感兴趣,他从中提取出了这个联系人的名字中的所有片段,如提取出orz的 o、r、z、or、rz、orz等等。现在他想请你统计有多少个长度为k的片段对(P[1], P[2], P[3], ..., P[k]),使得在该片段对中所有片段在S中出现次数之和为他的幸运数m?注意两个片段对不同当且仅当两个片段对的某一位的片段不同,两个片段不同当且仅当这两个片段在S中的位置不同
Input
第一行两个整数k和m,意义见题目描述;第二行给出一个字符串表示Tony喜欢的联系人名字S。
Output
输出一行一个整数ans,表示答案模1005060097。
Sample Input
aaaaa
Sample Output
HINT
【样例解释】
#include<cstdio>
#include<cstring>
#define ll long long
const int len(100000),MP(1005060097),g(5),lem(262144);
struct SamNode{int nx[26],pre,right,step;}sam[len*2+10];
int top=1,root=1,now=1,last,lastson;
int cnt[len+10],p[len*2+10],b[len+10];
int n,m,k;char str[len+10];
void insert(int x)
{
last=now;now=++top;sam[now].step=sam[last].step+1;sam[now].right=1;
for(;!sam[last].nx[x]&&last;last=sam[last].pre)
sam[last].nx[x]=now;
if(!last)sam[now].pre=root;
else
{
lastson=sam[last].nx[x];
if(sam[lastson].step==sam[last].step+1)sam[now].pre=lastson;
else
{
++top;
memcpy(sam[top].nx,sam[lastson].nx,sizeof(sam[top].nx));
sam[top].pre=sam[lastson].pre;
sam[top].step=sam[last].step+1;
sam[lastson].pre=sam[now].pre=top;
for(;sam[last].nx[x]==lastson&&last;last=sam[last].pre)
sam[last].nx[x]=top;
}
}
}
void update()
{
for(int i=1;i<=top;i++)cnt[sam[i].step]++;
for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
for(int i=top;i>=1;i--)p[cnt[sam[i].step]--]=i;
for(int i=top;i>=1;i--)
{
sam[sam[p[i]].pre].right+=sam[p[i]].right;
b[sam[p[i]].right]=(b[sam[p[i]].right]+1ll*sam[p[i]].right*(sam[p[i]].step-sam[sam[p[i]].pre].step))%MP;
}
} int R[lem+10],w[lem+10],wn,il,l,h;
void swap(int &a,int &b){if(a==b)return;a^=b;b^=a;a^=b;}
int power(int a,int b)
{
if(b<0)b=MP-1+b; long long t=1,y=a;
while(b){if(b&1)t=(t*y)%MP;y=(y*y)%MP;b>>=1;}
return (int)t;
}
struct Arr
{
void NTT(int *a,int l,int ty)
{
for(int i=0;i<l;i++)
if(i<R[i])swap(a[i],a[R[i]]);
for(int leng=2;leng<=l;leng<<=1)
{
int M=leng>>1;
wn=power(g,ty*((MP-1)/leng));
for(int i=1;i<M;i++)w[i]=(1ll*w[i-1]*wn)%MP;
for(int i=0;i<l;i+=leng)
{
for(int j=0;j<M;j++)
{
int x=a[i+j],y=(1ll*w[j]*a[i+j+M])%MP;
a[i+j]=x+y;a[i+j+M]=x-y;
a[i+j]-=a[i+j]>=MP?MP:0;
a[i+j+M]+=a[i+j+M]<0?MP:0;
}
}
}
if(ty==-1)
for(int i=0;i<l;i++)a[i]=(1ll*a[i]*il)%MP;
}
int a[lem+10];//只保留前m项
void mul(Arr &C)
{
NTT(a,l,1);
NTT(C.a,l,1);
for(int j=0;j<l;j++)a[j]=(1ll*a[j]*C.a[j])%MP;
NTT(a,l,-1);for(int j=m+1;j<l;j++)a[j]=0;
}
}X,Y,C;
void deal()
{
l=1;while(l<=m+m+1)l<<=1,h++;
for(int i=0;i<l;i++)R[i]=(R[i>>1]>>1|(i&1)<<(h-1));
il=power(l,MP-2);
}
int main()
{
// freopen("C.in","r",stdin);
// freopen("C.out","w",stdout);
scanf("%d%d",&k,&m);
scanf("%s",str);n=strlen(str);
for(int i=0;i<n;i++)insert(str[i]-'a');
update();deal();w[0]=1;
X.a[0]=1;for(int i=0;i<=m;i++)Y.a[i]=b[i];//,printf("%d\n",b[i])
for(;k;k>>=1,C=Y,Y.mul(C))
{
// printf("Y\n");
// for(int i=0;i<=m;i++)printf("%d\n",Y.a[i]);
if(k&1)C=Y,X.mul(C);
// printf("X\n");
// for(int i=0;i<=m;i++)printf("%d\n",Y.a[i]);
}
printf("%d",X.a[m]);
return 0;
}
BZOJ 4175: 小G的电话本 SAM+FFT的更多相关文章
- BZOJ 4175 小G的电话本 ——NTT
后缀自动机统计出现了各种次数的串的和. 就是所谓的生成函数 然后FFT卷积即可. 卷积快速幂$n\log n \log n$ 注意一下实现,可以少两次NTT #include <map> ...
- BZOJ4175 : 小G的电话本
用后缀树统计出出现了x次的本质不同的子串的个数,最后再乘以x,得到一个多项式. 这个多项式常数项为0,但是一次项不为0. 于是把整个多项式除以一次项,通过多项式求ln和多项式求exp求出它的幂. 最后 ...
- [BZOJ 1563] [NOI 2009] 诗人小G(决策单调性)
[BZOJ 1563] [NOI 2009] 诗人小G(决策单调性) 题面 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中,注意一行中可以放的句子数目是没有限制的.小 G ...
- C语言实现电话本 动态开辟 信息存储于文件
下面是我用C写的一个电话本小项目,实现的功能有:添加 删除 修改 查找 排序 清空 显示,功能还是比较全的,内存也是动态开辟的.能存储于本地,能从本地读出并显示 头文件部分代码,contact.h: ...
- BZOJ 5028 小z的加油站
bzoj链接 Time limit 10000 ms Memory limit 262144 kB OS Linux 感想 树上动态gcd的第二题也好了. [x] BZOJ 2257 [JSOI200 ...
- 微信电话本可免费拨打网络电话 通话一分钟约300K流量
微信电话本新版本于昨日晚间发布,这是一款智能通讯增强软件,通话双方都下载此APP并开通免费通话功能就能使用微信电话本拨打免费网络电话,在对方无法接通情况下还能将音频转向语音信箱,微信电话本目前支持An ...
- C++之路进阶——codevs2933(诗人小G)
2933 诗人小G 2009年NOI全国竞赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 小G是一个出色的诗人 ...
- 苹果IPhone手机由于更新了IOS7 Beta测试版导致“激活出错”后,如何还原电话本和照片方法
苹果这狗日的,手段果然狠,因为用户提前升级了测试版又没有更新正式版,就突然把手机变砖头,既不让升级正式版,也不让备份手机中的信息,确实有必要这样吗? 我的手机是IPone4s,在看了6月Apple W ...
- Android-->发送短信页面实现(短信发送以及群发和从电话本中选择联系人)-----------》2
分析下怎么写 首先,我们需要一个输入框,可以手动的输入手机号码, 其次,很少有人愿意手动输入,那么我们需要提供一个按钮来给我们的用户选择自己电话本中的联系人(一次可以选择多个即群发) 然后,我们需要一 ...
随机推荐
- linux下使用c判断文件夹是否为空的小程序
自己写了一个 判断文件夹是否为空的小代码 //文件夹操作相关的函数的帮助$: man 3 readdir #include <stdio.h> #include <sys/types ...
- AutoHotkey常用配置
; 开发常用 ^e:: run D:\soft\java\MyEclipse for Spring 2014\myeclipseforspring.exe return ^d:: run D:\sof ...
- 编写BeanFactory
/** * 一个创建Bean对象的工厂 * * Bean:在计算机英语中,有可重用组件的含义. * JavaBean:用java语言编写的可重用组件. * javabean > 实体类 * * ...
- HDU2874【LCA(模板)】
第一题LCA,代码参考自:Ice_Crazy 思路: 这个最短路算法是想都别想了,可以看出这幅图就是树嘛,那么对于查询就是求树上两个结点最短距离. 这里就是利用LCA的tarjan离线算法. 算法的大 ...
- poj2241 The Tower of Babylon
The Tower of Babylon 题意:给你n种石头,长x,宽y,高z,每种石头数目无限,一块石头能放到另一块上的条件是:长和宽严格小于下面的石头.问叠起来的最大高度. /* 有些类似“叠箱子 ...
- Java IO 输入和输出流
数据流是指一组有顺序的,有起点和终点的字节集合. 最初的版本中,java.io 包中的流只有普通的字节流,即以 byte 为基本处理单位的流.字节流用来读写 8 位的数据,由于不会对数据做任何转换,因 ...
- ios 自定义cell类中获取当前controller push
有时候在自定义cell的过程中,当cell中又button的时候,把button的点击时间写在cell中的时候,需要获取到cell的父视图控制器然后push,可以自建一个类,命名为: GetCurre ...
- SQL Server插入中文乱码
如果数据库的Collocation是英文的,字段是varchar类型,向表中插入中文数据,会出现乱码. 解决方法: 方法1. 修改varchar 为 nvarchar类型, 并在插入数据前加N,例如: ...
- JS高级学习历程-6
PHP菜鸟学习历程-6 [闭包案例] 1 闭包创建数组 <!DOCTYPE html> <html lang="en"> <head> < ...
- vue中做出购物车的功能
效果展示: 一:html结构 <div id="buyButton" class="btn-buy"> <button onclick=&qu ...