「CF645E」 Intellectual Inquiry
题目链接
题意
有一个长为\(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的更多相关文章
- 「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
- 「JavaScript」四种跨域方式详解
超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...
- 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management
写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...
- 「2014-3-18」multi-pattern string match using aho-corasick
我是擅(倾)长(向)把一篇文章写成杂文的.毕竟,写博客记录生活点滴,比不得发 paper,要求字斟句酌八股结构到位:风格偏杂文一点,也是没人拒稿的.这么说来,arxiv 就好比是 paper 世界的博 ...
- 「2014-3-17」C pointer again …
记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...
- 「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 =& ...
随机推荐
- 报错 source-1.6 中不支持 diamond运算符
报错 source-1.6 中不支持 diamond运算符 解决方式 在pom.xml文件中修改 <plugin> <groupId>org.apache.maven.plug ...
- JUC---08ForkJion(分支合并)
一.什么是ForkJion Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为 ...
- D. 停不下来的团长奥尔加 动态规划
题目描述 分析 设\(f[i]\) 为从 \(i\) 走到 \(i+1\) 的步数 初始值 \(f[i]=2\) 则 \(f[i]=\sum_{i=p[i]}^{i}f[i]\) 考试的时候用树状数组 ...
- 框架-SPI四种模式+通用设备驱动实现
目录 前言 笔录草稿 SPI介绍 SPI四种模式 ** SPI 驱动框架 ** 框架 前言 SPI 介绍为搜集百度资料+个人理解 其余为原创(有误请指正) 集四种模式于一身 笔录草稿 SPI介绍 SP ...
- 浅谈分布式共识算法raft
前言:在分布式的系统中,存在很多的节点,节点之间如何进行协作运行.高效流转.主节点挂了怎么办.如何选主.各节点之间如何保持一致,这都是不可不面对的问题,此时raft算法应运而生,专门 用来解决上述问题 ...
- sqlsugar入门(4)-修改源码支持多主键保存ISaveable
1.查看其它接口发现少了一个最重要的SaveBuilder.此文件是存放sql模板,where条件,select解析,组装成tosqlstring的最后一个类. 添加文件 using System; ...
- Django之富文本(获取内容,设置内容)
富文本 1.Rich Text Format(RTF) 微软开发的跨平台文档格式,大多数的文字处理软件都能读取和保存RTF文档,其实就是可以添加样式的文档,和HTML有很多相似的地方 图示 2.tin ...
- 适合 C++ 新手学习的开源项目——在 GitHub 学编程
作者:HelloGitHub-小鱼干 俗话说:万事开头难,学习编程也是一样.在 HelloGitHub 的群里,经常遇到有小伙伴询问编程语言如何入门方面的问题,如: 我要学习某一门编程语言,有什么开源 ...
- 843. Guess the Word —— weekly contest 86
题目链接:https://leetcode.com/problems/guess-the-word/description/ 占坑 据说要用启发式算法,可参考下述答案进行学习:https://leet ...
- Java入门(2)
阅读书目:Java入门经典(第7版) 作者:罗格斯·卡登海德 一个简单的计算平方根的程序: 1 package com.java24hours; 2 3 public class Root { 4 p ...