题目链接

CF645E

题意

有一个长为\(n\)的由小写字母组成的字符串,需要用小写字母再填\(m\)位,使最后的字符串中本质不同的子串数量尽量多,答案对\(10^9+7\)取模。

本题数据:\(n,m\le 10^6\),事实上\(n\le10^6,m\le10^{18}\)也可以做

solution

先考虑\(m=0\)的情况,此时字符串确定,令\(f[i]\)表示前\(i\)位字符串中本质不同的子串数量,考虑到第\(i\)位时,新产生的子串是前\(i-1\)位所有本质不同的字符串最后接上第\(i\)位以及第\(i\)位自身。

于是\(f[i]=f[i-1]+f[i-1]+1\),但如果\(a[i](i出的字母)\),曾经在\(last[a[i]]\)处出现过,那么前\(last[a[i]]-1\)位字符串的子串与\(a[i]\)组合而成的字符串会重复,所以\(f[i]=f[i-1]+f[i-1]-f[last[a[i]-1]\)

当\(m>0\)时,为使答案最大,我们需要让靠前的\(last[a[i]]\)尽量小,所以填写时按\(last[i]\)从小到大依次填写一定最优,于是\(O(n+m)\)扫一遍,就可以通过CF645E此题。

发现填写序列时每\(k\)位一个循环,而\(k\le26\),所以可以矩阵快速幂优化到\(O(n+k^3log(m))\),能通过\(m\le10^{18}\)的数据

code

//O(n+m)算法
#include<bits/stdc++.h>
using namespace std;
const int M=1e9+7;
const int N=2e6+10;
int n,m,k,a[N],vis[N],q[N],cnt,f[N],last[N],tot=0;
char s[N];
inline int add(int x,int y,int mod=M){return (x+y>=mod)?x+y-mod:x+y;}
inline int dec(int x,int y,int mod=M){return (x-y<0)?x-y+mod:x-y;}
int main(){
scanf("%d%d",&m,&k);cnt=k;
scanf("%s",s+1);n=strlen(s+1);
for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1;
for(int i=n;i>=1;--i)
if(!vis[a[i]]) q[--cnt]=a[i],vis[a[i]]=1;
for(int i=1;i<=k;++i) if(!vis[i]) q[--cnt]=i;
memset(last,-1,sizeof(last));
for(int i=1;i<=n+m;++i){
if(i>n) a[i]=q[tot],tot=add(tot,1,k);
if(last[a[i]]!=-1) f[i]=dec(add(f[i-1],f[i-1]),f[last[a[i]]-1]);
else f[i]=add(add(f[i-1],f[i-1]),1);
last[a[i]]=i;
}
printf("%d\n",f[n+m]+1);
return 0;
}
//O(n+k^3log(m))算法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e9+7;
const int N=4e6+10;
const int K=210;
int n,k,a[N],vis[N],q[N],cnt,f[N],last[N],tot=0,pw[N];
ll m;
char s[N];
inline int add(int x,int y,int mod=M){return (x+y>=mod)?x+y-mod:x+y;}
inline int dec(int x,int y,int mod=M){return (x-y<0)?x-y+mod:x-y;}
struct matrix{
int c[K][K];
void build(int d=0){
for(int i=1;i<=k+1;++i)
for(int j=1;j<=k+1;++j) c[i][j]=0;
for(int i=1;i<=k+1;++i) c[i][i]=d;
}
matrix operator *(matrix x){
matrix ret;ret.build();
for(int i=1;i<=k+1;++i)
for(int j=1;j<=k+1;++j)
for(int w=1;w<=k+1;++w)
ret.c[i][j]=add(ret.c[i][j],1ll*c[i][w]*x.c[w][j]%M);
return ret;
}
};
matrix operator ^(matrix a,ll k){
matrix ret;ret.build(1);
while(k){
if(k&1) ret=ret*a;
a=a*a;k>>=1;
}
return ret;
}
int main(){
scanf("%lld%d",&m,&k);cnt=k;
scanf("%s",s+1);n=strlen(s+1);
for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1;
for(int i=n;i>=1;--i)
if(!vis[a[i]]) q[--cnt]=a[i],vis[a[i]]=1;
for(int i=1;i<=k;++i) if(!vis[i]) q[--cnt]=i;
memset(last,-1,sizeof(last));
int t=min(m,k*1ll);
for(int i=1;i<=n+t;++i){
if(i>n) a[i]=q[tot],tot=add(tot,1,k);
if(last[a[i]]!=-1) f[i]=dec(add(f[i-1],f[i-1]),f[last[a[i]]-1]);
else f[i]=add(add(f[i-1],f[i-1]),1);
last[a[i]]=i;
}
if(m==t) printf("%d\n",f[n+m]+1);
else{
matrix A;A.build();
pw[0]=1;for(int i=1;i<=k+1;++i) pw[i]=2ll*pw[i-1]%M;
A.c[1][k+1]=1;
for(int i=2;i<=k+1;++i){
for(int j=1;j<i-1;++j)
A.c[i][j]=dec(M,pw[i-j-1]);
A.c[i][i-1]=M-1;
A.c[i][k+1]=add(A.c[i][k+1],pw[i-1]);
}
ll c=(m-1)/k,ans=0;m-=c*k;
A=A^c;
for(int i=0;i<=k;++i) ans=add(ans,1ll*f[n+i]*A.c[m+1][i+1]%M);
printf("%d\n",ans+1);
}
return 0;
}

「CF645E」 Intellectual Inquiry的更多相关文章

  1. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  2. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  3. JavaScript OOP 之「创建对象」

    工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...

  4. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  5. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  6. 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management

    写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...

  7. 「2014-3-18」multi-pattern string match using aho-corasick

    我是擅(倾)长(向)把一篇文章写成杂文的.毕竟,写博客记录生活点滴,比不得发 paper,要求字斟句酌八股结构到位:风格偏杂文一点,也是没人拒稿的.这么说来,arxiv 就好比是 paper 世界的博 ...

  8. 「2014-3-17」C pointer again …

    记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...

  9. 「2014-3-13」Javascript Engine, Java VM, Python interpreter, PyPy – a glance

    提要: url anchor (ajax) => javascript engine (1~4 articles) => java VM vs. python interpreter =& ...

随机推荐

  1. Flutter - 自定义Dialog弹窗

    ------------恢复内容开始------------ Flutter - 自定义Dialog弹窗 应用场景:app系统版本升级弹窗,系统退出登录弹窗,首页广告弹窗,消息中心弹窗,删除文件弹窗等 ...

  2. 安卓WebSocket使用

    引入jar包: implementation "org.java-websocket:Java-WebSocket:1.4.0"implementation "org.s ...

  3. 栈&队列&并查集&哈希表(julyedu网课整理)

    date: 2018-11-25 08:31:30 updated: 2018-11-25 08:31:30 栈&队列&并查集&哈希表(julyedu网课整理) 栈和队列 1. ...

  4. non-local denoising methods

    NL-Means算法 在噪声先验为高斯噪声的基础上, 进行non-local的平均,在2005年由Baudes提出,该算法使用自然图像中普遍存在的冗余信息来去噪声.与常用的双线性滤波.中值滤波等利用图 ...

  5. Azure Data Factory(一)入门简介

    一,引言 今天分享一个新的Azure 服务-----Azure Data Factory(Azure 数据工厂),怎么理解,参考根据官方解释-----数据工厂解释:大数据需要可以启用协调和操作过程以将 ...

  6. 从入门到掌握 - 系统学习shell语言

    简介 什么是 shell Shell是一种程序或命令行解释程序,用于解释用户直接输入的用户命令或从文件中读取的用户命令,然后将 它们传递给操作系统以进行操作或处理.要注意,这个过程是解释而不编译脚本, ...

  7. Python爬虫之多线程

    详情点我跳转 关注公众号"轻松学编程"了解更多. 多线程 在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的多线程! 为什么这么说,我们先明确一个概念,全 ...

  8. 【Luogu】P1306 斐波那契公约数 题解

    原题链接 嗯...很多人应该是冲着这个标题来的 (斐波那契的魅力) 1.分析题面 点开题目,浏览一遍题目,嗯?这么简单?还是蓝题? 再看看数据范围,感受出题人深深的好意... \(n,m \leq 1 ...

  9. 【QT】QThread源码浅析

    本章会挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...

  10. python爬虫00什么是爬虫

    用一个自动化的程序把网站背后的程序爬取下来. 在互联网上许许多多的网站,他们都是托管在服务器上的,这些服务器24小时运行着,刻刻 等待着别人的请求.所以,爬虫首先会模拟请求,就好像你在浏览器输入网址, ...