4180: 字符串计数

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 164  Solved: 75

Description

SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999。
他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', 'D'。现在他要求蒟蒻yts1999构造一个新的字符串S,构造的方法是:进行多次操作,每一次操作选择T的一个子串,将其加入S的末尾。
对于一个可构造出的字符串S,可能有多种构造方案,Oxer定义构造字符串S所需的操作次数为所有构造方案中操作次数的最小值。
Oxer想知道对于给定的正整数N和字符串T,他所能构造出的所有长度为N的字符串S中,构造所需的操作次数最大的字符串的操作次数。
蒟蒻yts1999当然不会做了,于是向你求助。

Input

第一行包含一个整数N,表示要构造的字符串长度。
第二行包含一个字符串T,T的意义如题所述。

Output

输出文件包含一行,一个整数,为你所求出的最大的操作次数。

Sample Input

5
ABCCAD

Sample Output

5

HINT

【样例说明】
例如字符串"AAAAA",该字符串所需操作次数为5,不存在能用T的子串构造出的,且所需操作次数比5大的字符串。
【数据规模和约定】
对于100%的数据,1 ≤ N ≤ 10^18,1 ≤ |T| ≤ 10^5。

Source

【分析】

  好题啊。我没想到。。

  要用一种稍微转化一下的思维?

  要算n最多操作次数,可以二分答案,然后询问操作次数为x的区间最小长度是多少。【我个人觉得这样想也不简单啊。

  考虑如果S确定的话,其实是贪心的,匹配到不能匹配的时候断掉,成为新的一段。

  在SAM上就是没有儿子的后继之后,就跳回根。

  所以其实(10^18的时候你应该看出来要矩乘了),矩阵中不需要存SAM的每个点,也不能存,只要存现在是什么颜色就好了。

  保证断掉的话,就是f[i][j]表示第i为开头的子串最短多少后面接j就会断。

  这个很好求,先做SAM,求出mn[x][i]表示x这个点后面接最短多少的子串再接j之后就会断。

  mn[x][i]=min(mn[son][i]+1)。

  f[i][j]=mn[1的i儿子][j]。

  然后x次操作就是f[i][j]^x,矩阵“乘法”的运算实际上是求和取min。

  【看代码吧!

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 100010
#define LL long long
#define INF 0xfffffff
#define inf 1LL<<60 LL n;
int mymin(int x,int y) {return x<y?x:y;} struct node
{
int pre,son[],step;
}t[Maxn*];
bool vis[*Maxn]; int mn[*Maxn][]; struct sam
{
int last,tot;
void extend(int k)
{
int np=++tot,p=last;
t[np].step=t[p].step+;
while(p&&!t[p].son[k])
{
t[p].son[k]=np;
p=t[p].pre;
}
if(!p) t[np].pre=;
else
{
int q=t[p].son[k];
if(t[q].step==t[p].step+) t[np].pre=q;
else
{
int nq=++tot;
memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
t[nq].step=t[p].step+;
t[nq].pre=t[q].pre;
t[q].pre=t[np].pre=nq;
while(p&&t[p].son[k]==q)
{
t[p].son[k]=nq;
p=t[p].pre;
}
}
}
last=np;
}
void dfs(int x)
{
if(vis[x]) return;
vis[x]=;
for(int i=;i<=;i++) mn[x][i]=INF;
for(int i=;i<=;i++)
{
if(!t[x].son[i]) mn[x][i]=;
else
{
dfs(t[x].son[i]);
for(int j=;j<=;j++) mn[x][j]=mymin(mn[x][j],mn[t[x].son[i]][j]+);
}
}
}
}sam; char s[Maxn]; struct Matrix
{
LL w[][];
Matrix() {memset(w,,sizeof(w));}
inline friend Matrix operator * (const Matrix A,const Matrix B)
{
Matrix ret;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
ret.w[i][j]=inf;
for(int k=;k<=;k++) ret.w[i][j]=min(ret.w[i][j],A.w[i][k]+B.w[k][j]);
}
return ret;
}
inline friend Matrix operator ^ (const Matrix A,LL k)
{
Matrix ret,tmp=A;
for(int i=;i<=;i++) for(int j=;j<=;j++) ret.w[i][j]=(i==j)?:;
for (;k;k>>=,tmp=tmp*tmp) if(k&) ret=ret*tmp;
return ret;
}
}Q; bool check(LL x)
{
Matrix B=Q^x;
LL mn=inf;
for(int i=;i<=;i++) for(int j=;j<=;j++) mn=min(mn,B.w[i][j]);
return mn>=n;
} int main()
{
scanf("%lld",&n);
scanf("%s",s);
int ll=strlen(s);
sam.tot=sam.last=;
for(int i=;i<ll;i++) sam.extend(s[i]-'A'+);
memset(vis,,sizeof(vis));
sam.dfs(); for(int i=;i<=;i++) for(int j=;j<=;j++) Q.w[i][j]=mn[t[].son[i]][j]; LL l=,r=n,ans;
while(l<r)
{
LL mid=(l+r)>>;
if(check(mid)) r=mid;
else l=mid+;
}
printf("%lld\n",r);
return ;
}

看了CA爷的代码,感觉我的矩乘好看多啦!

写在结构体里面很有条理!!

2017-04-17 20:02:16

【BZOJ 4180】 4180: 字符串计数 (SAM+二分+矩阵乘法)的更多相关文章

  1. BZOJ4180:字符串计数(SAM,二分,矩阵乘法)

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  2. BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999.   他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C ...

  3. 【BZOJ-4180】字符串计数 后缀自动机 + 矩阵乘法

    4180: 字符串计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 146  Solved: 66[Submit][Status][Discuss] ...

  4. BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法

    标题效果:给定的长度m数字字符串s.求不包括子s长度n数字串的数目 n<=10^9 看这个O(n)它与 我们不认为这 令f[i][j]长度i号码的最后的字符串j位和s前者j数字匹配方案 例如,当 ...

  5. BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)

    首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。 PS:WA了N久改了3次终于A了QAQ CODE: #include<cst ...

  6. 【BZOJ 2510】 2510: 弱题 (矩阵乘法、循环矩阵的矩阵乘法)

    2510: 弱题 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 374  Solved: 196 Description 有M个球,一开始每个球均有一 ...

  7. POJ 3233 Matrix Power Series 二分+矩阵乘法

    链接:http://poj.org/problem?id=3233 题意:给一个N*N的矩阵(N<=30),求S = A + A^2 + A^3 + - + A^k(k<=10^9). 思 ...

  8. 【BZOJ】2875: [Noi2012]随机数生成器(矩阵乘法+快速乘)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2875 矩阵的话很容易看出来.....我就不写了.太水了. 然后乘法longlong会溢出...那么我 ...

  9. BZOJ.1875.[SDOI2009]HH去散步(DP 矩阵乘法)

    题目链接 比较容易想到用f[i][j]表示走了i步后到达j点的方案数,但是题目要求不能走上一条走过的边 如果这样表示是不好转移的 可以考虑边,f[i][j]表示走了i步后到达第j条边的方案数,那么有 ...

随机推荐

  1. 4163 hzwer与逆序对 (codevs + 权值线段树 + 求逆序对)

    题目链接:http://codevs.cn/problem/4163/ 题目:

  2. 1030 大数进制转换(51Nod + JAVA)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1030 题目: 代码实现如下: import java.mat ...

  3. Function.prototype.bind 简介

    bind可以解决两种问题: 1. 可以改变一个函数的 this 指向 2. 可以实现偏函数等高阶功能 本文暂且讨论第一个功能 USE CASE var foo = { x: 3 } var bar = ...

  4. jQuery的validation插件(验证表单插件)

    更完整的参考:http://www.runoob.com/jquery/jquery-plugin-validate.html 验证隐藏字段的使用(验证通过后ajax提交表单):http://www. ...

  5. Python排序算法之插入排序

    # 插入排序的工作原理是,对于每个未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.## 步骤:## 从第一个元素开始,该元素可以认为已经被排序# 取出下一个元素,在已经排序的元素序列中从后 ...

  6. Tutorial 1: Serialization

    转载自:http://www.django-rest-framework.org/tutorial/1-serialization/#tutorial-1-serialization Tutorial ...

  7. ansible安装配置及最佳实践roles

    ansible是什么? ansible是一款轻量级配置管理工具,用于远程批量部署.安装.配置.类似的还有puppet.saltstack,各有所长,任君自选. 官方文档:http://docs.ans ...

  8. Homestead在windows7 下的搭建

    遇到的问题有 1.Homestead 的版本问题,教程git版本是 v5,最新是v7的,如果用最新,就要求vagrant的版本是 2.0的: 2.启动homestead后,出现 No input fi ...

  9. js获取系统时间

    //------------------------------------获取系统日期时间 var oDate=new Date(); //alert(oDate.getFullYear());// ...

  10. JAVA封装消息中间件调用二(kafka消费者篇)

    上一遍我简单介绍了kafka的生成者使用,调用方式比较简单,今天我给大家分享下封装kafka消费者,作为中间件,我们做的就是最大程度的解耦,使业务方接入我们依赖程度降到最低. 第一步,我们先配置一个消 ...