BZOJ4175 : 小G的电话本

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

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

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

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

#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=262144,K=17,inf=~0U>>2,S=27,M=200010,P=1005060097,G=5;
char s[M];
int n,m,x,i,j,k,C;
int a[N+10],b[N+10],tmp[N],tmp2[N],g[K+1],ng[K+1],inv[N+10],inv2;
int text[M],root,last,pos,need,remain,acnode,ace,aclen,size[M];
inline int min(int a,int b){return a<b?a:b;}
struct node{int st,en,lk,son[S];inline int len(){return min(en,pos+1)-st;}}tree[M];
inline int new_node(int st,int en=inf){return tree[++last].st=st,tree[last].en=en,last;}
inline int acedge(){return text[ace];}
inline void addedge(int node){
  if(need)tree[need].lk=node;
  need=node;
}
inline bool down(int node){
  if(aclen>=tree[node].len())return ace+=tree[node].len(),aclen-=tree[node].len(),acnode=node,1;
  return 0;
}
inline void init(){
  need=last=remain=ace=aclen=0;
  root=acnode=new_node(pos=-1,-1);
}
inline void extend(int c){
  text[++pos]=c;need=0;remain++;
  while(remain){
    if(!aclen)ace=pos;
    if(!tree[acnode].son[acedge()])tree[acnode].son[acedge()]=new_node(pos),addedge(acnode);
    else{
      int nxt=tree[acnode].son[acedge()];
      if(down(nxt))continue;
      if(text[tree[nxt].st+aclen]==c){aclen++;addedge(acnode);break;}
      int split=new_node(tree[nxt].st,tree[nxt].st+aclen);
      tree[acnode].son[acedge()]=split;
      tree[split].son[c]=new_node(pos);
      tree[nxt].st+=aclen;
      tree[split].son[text[tree[nxt].st]]=nxt;
      addedge(split);
    }
    remain--;
    if(acnode==root&&aclen)aclen--,ace=pos-remain+1;
    else acnode=tree[acnode].lk?tree[acnode].lk:root;
  }
}
void dfs(int x,int sum){
  sum+=tree[x].len();
  if(tree[x].en==inf&&pos-sum+1<=n)size[x]=1;
  for(int i=0;i<S;i++)if(tree[x].son[i]){
    int j=tree[x].son[i];
    dfs(j,sum),size[x]+=size[j];
  }
  if(size[x])a[size[x]]=(a[size[x]]+tree[x].len())%P;
}
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;}
inline void NTT(int*a,int n,int t){
  for(int i=1,j=0;i<n-1;i++){
    for(int s=n;j^=s>>=1,~j&s;);
    if(i<j){int k=a[i];a[i]=a[j];a[j]=k;}
  }
  for(int d=0;(1<<d)<n;d++){
    int m=1<<d,m2=m<<1,_w=t==1?g[d]:ng[d];
    for(int i=0;i<n;i+=m2)for(int w=1,j=0;j<m;j++){
      int&A=a[i+j+m],&B=a[i+j],t=1LL*w*A%P;
      A=B-t;if(A<0)A+=P;
      B=B+t;if(B>=P)B-=P;
      w=1LL*w*_w%P;
    }
  }
  if(t==-1)for(int i=0,j=inv[n];i<n;i++)a[i]=1LL*a[i]*j%P;
}
void getinv(int*a,int*b,int n){
  if(n==1){b[0]=pow(a[0],P-2);return;}
  getinv(a,b,n>>1);
  int k=n<<1,i;
  for(i=0;i<n;i++)tmp[i]=a[i];
  for(i=n;i<k;i++)tmp[i]=b[i]=0;
  NTT(tmp,k,1),NTT(b,k,1);
  for(i=0;i<k;i++){
    b[i]=(ll)b[i]*(2-(ll)tmp[i]*b[i]%P)%P;
    if(b[i]<0)b[i]+=P;
  }
  NTT(b,k,-1);
  for(i=n;i<k;i++)b[i]=0;
}
inline void getln(int*a,int*b,int n){
  getinv(a,tmp2,n);
  int k=n<<1,i;
  for(i=0;i<n-1;i++)b[i]=(ll)a[i+1]*(i+1)%P;
  for(i=n-1;i<k;i++)b[i]=0;
  NTT(b,k,1),NTT(tmp2,k,1);
  for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp2[i]%P;
  NTT(b,k,-1);
  for(i=n-1;i;i--)b[i]=(ll)b[i-1]*inv[i]%P;b[0]=0;
}
void getexp(int*a,int*b,int n){
  if(n==1){b[0]=1;return;}
  getexp(a,b,n>>1);
  getln(b,tmp,n);
  int k=n<<1,i;
  for(i=0;i<n;i++){tmp[i]=a[i]-tmp[i];if(tmp[i]<0)tmp[i]+=P;}
  if((++tmp[0])==P)tmp[0]=0;
  for(i=n;i<k;i++)tmp[i]=b[i]=0;
  NTT(tmp,k,1),NTT(b,k,1);
  for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp[i]%P;
  NTT(b,k,-1);
  for(i=n;i<k;i++)b[i]=0;
}
int main(){
  scanf("%d%d%s",&m,&x,s+1);
  if(m>x)return puts("0"),0;
  n=std::strlen(s+1);
  for(i=1;i<=n;extend(s[i++]-‘a‘));extend(26);
  pos--,dfs(root,0);
  for(i=0;i<=x;i++)a[i]=1LL*a[i]*i%P;
  C=a[1],j=pow(C,P-2);
  for(i=0;i<x;i++)a[i]=1LL*a[i+1]*j%P;
  for(i=x;i<k;i++)a[i]=0;
  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;
  for(inv[1]=1,i=2;i<=N;i++)inv[i]=(ll)(P-inv[P%i])*(P/i)%P;inv2=inv[2];
  for(k=1;k<=x;k<<=1);
  getln(a,b,k);
  for(i=0;i<k;i++)b[i]=1LL*b[i]*m%P;
  getexp(b,a,k);
  return printf("%d",1LL*a[x-m]*pow(C,m)%P),0;
}

  

时间: 2024-11-10 13:18:24

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

微信电话本的未来在农村

一夜之间,微信电话本就在用户的手机联系人之间广为流传,似乎微信电话本真的火.真的如此吗?何玺认为,微信电话本的火爆可能是暂时的假象,就它目前的功能不做改进的话,用不了多久,它就将成为过去. 关于微信电本 据微信团队介绍,使用微信电话本拨打电话,需要通话双方都下载该APP并开通免费通话功能.免费通话功能无法在对方没有安装微信电话本.或者没有微信登录(安装了微信的情况下).或者号码未开通免费功能的情况下直接拨打. "微信电话本"通话功能本身免费,但在2G/3G/4G网络下会消耗流量,WiF

微信电话本可以正常服务了 还我美女!

微信电话本刚一上线,ytkah第一时间下载来试一下,可惜一直提示“激活失效”,没法和小美女免费通话让她失望了.只想大声对微信电话本嚎“还我美女!!”太火的缘故?服务器宕机?下午终于知道什么情况了.微信电话本公众号发布消息如下 昨天上线后,小伙伴们的热情把我们点燃了!热量蔓延到了服务器.电缆.机房,以致服务出现不稳定!程序猿同学边享受甜蜜的痛苦边熬夜修复,小编实在熬不住就睡觉去了,早起一看,通讯录又多了一堆免费通话小伙伴,才知道服务已经恢复,赶紧来告诉大家,果断打开电话本,免费聊起来吧!

java模拟而一个电话本操作

哈哈,大家平时都在使用电话本,下面使用java来模拟而一个简单的电话本吧... 首先给出联系人的抽象类 package net.itaem.po; /** * * 电话人的信息 * */ public class User { private String name; private String phoneNumber; private String companyName; private String email; private String address; private Strin

jdbc电话本项目

整体思路:在登陆之后才能查看自己的电话本,电话本中包含用户名,联系人名字,电话,性别,分类: 1.登陆注册页面--数据库User表,注册登陆使用 2.电话本的前段显示,用表格和表单, 3.创建存取的电话本的表的类,实现各种setget方法及构造方法 4.电话本需要查询,删除,添加,修改的功能,创建java文件实现这些方法 5.创建各种方法的servlet,实现这些功能, 注意:进行非空验证,还有就是在电话本的存储的表中要有隐藏的id,通过前台传入id,作为主键去判断实现那些方法,在登陆之后要注意

记一次开发:Qt简单电话本程序

前言 断断续续学习C++一年了,现在要做课设,觉得控制台界面实在太难看,于是用Qt做一个图形化的程序出来. 学习Qt也没有多久,只是了解了个大概,这次开发基本上是啃了2天的官方帮助文档,然后利用各种Qt提供的轮子实现的.有些地方做的确实还很不完善,不过似乎没有什么致命的bug. 代码质量底下,谨慎模仿. Qt真的是一个很好的C++扩展库,学习完C++觉得没有用武之地的可以去学习一下Qt来开发几个图形化软件来练练手. 项目介绍 实现一个简单的电话本程序,能够实现添加.查找.修改.删除.保存到文件等

用结构体实现一个电话本

结构体是c语言又一个存储数据的类型,那么用结构体怎么实现一个简单的可以存储1000个人信息的电话本呢?     一.首先需要定义一个结构体,包含一个人的信息(比如姓名,性别,年龄,电话,住址等等).我们先来定义一个结构体.     typedef struct Pdhb-info     {       char name[5];       char sex[3];       int age;       char tele[12];       char addr[30];     }Pd

ios开发-电话本的设计与实现

#import <UIKit/UIKit.h> #import "SubViewController.h" @interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,SubViewControllerDelegate> @end #import "SubViewController.h" @interface SubViewCo

BZOJ 1563 诗人小G(四边形优化)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1563 题意: 思路:设s[i]表示前i个句子的长度和,那么有转移方程: 有大牛证明这个满足四边形不等式,证明应该 比较复杂.在<1D/1D动态规划优化初步>这篇文章中,作者说实战中可以直接打表看看是不是满足,感觉还是比较实用的.不管那么多了,现在我们知道了满 足四边形不等式,也就是满足决策点单调.比如f[i]是用j更新的,那么i之后的点不可能用j之前的点更新,这就是决策单调性.那么我

NOI 2009A 诗人小G

NOI 2009A 诗人小G 诗人小G [问题描述] 小G是一个出色的诗人,经常作诗自娱自乐.但是,他一直被一件事情所困扰,那就是诗的排版问题. 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中, 注意一行中可以放的句子数目是没有限制的.小G给每首诗定义了一个行标准长度(行的长度为一行中符号的总个数),他希望排版后每行的长度都和行标准长度相差不远.显然排版时,不应改变原有的句子顺序,并且小G不允许把一个句子分在两行或者更多的行内.在满足上面两个条件的情况下,小G对于排