BZOJ2099: [Usaco2010 Dec]Letter 恐吓信
给两个长度不超过50000的串,A串可每次截连续一段复制出来,求最少复制几次能得到B串。
方法一:SAM。不会。
嗯好会了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
//#include<iostream>
//#include<time.h>
using namespace std; int n,m;
#define maxn 200011*2
char s[maxn],p[maxn];
struct SAM
{
int ch[maxn][],size,last,pre[maxn],pos[maxn];
SAM()
{
size=;
memset(ch[],,sizeof(ch[]));
pre[]=-;
}
int idx(char c) {return c-'A';}
void insert(char c,int p)
{
int id=idx(c),x=++size;
memset(ch[x],,sizeof(ch[x])); pos[x]=p;
int y=last;
for (;y!=- && !ch[y][id];y=pre[y]) ch[y][id]=x;
last=x;
if (y==-) pre[x]=;
else
{
if (pos[ch[y][id]]==pos[y]+) pre[x]=ch[y][id];
else
{
int z=ch[y][id],w=++size;
memcpy(ch[w],ch[z],sizeof(ch[z]));
pos[w]=pos[y]+; pre[w]=pre[z];
pre[z]=pre[x]=w;
for (;y!=- && ch[y][id]==z;y=pre[y]) ch[y][id]=w;
}
}
}
}sam; int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
{
char c;while (!((c=getchar())>='A' && c<='Z'));
sam.insert(c,i);
}
for (int i=;i<=m;i++) while (!((p[i]=getchar())>='A' && p[i]<='Z'));
int pos=,ans=;
while (pos<=m)
{
int now=;
while (pos<=m && sam.ch[now][p[pos]-'A']) now=sam.ch[now][p[pos]-'A'],pos++;
// cout<<endl;
ans++;
}
printf("%d\n",ans);
return ;
}
方法二:其实就是拿B去A上面匹配若干次。多次匹配的话可以把A先建个后缀数组,然后每次二分到B的位置搞匹配。匹配一次怕太慢的话,用hash吧!二分匹配长度找到第一个不可匹配的位置,就可以算匹配长度啦!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
//#include<iostream>
using namespace std; int n,m;
#define maxn 50011
char t[maxn],p[maxn],c;
int ht[maxn],hp[maxn];
int sa[maxn],cnt[maxn],rank[maxn],y[maxn];
void makesa(char* s)
{
int n=strlen(s),m=;
for (int i=;i<m;i++) cnt[i]=;
for (int i=;i<n;i++) cnt[rank[i]=s[i]-'A']++;
for (int i=;i<m;i++) cnt[i]+=cnt[i-];
for (int i=n-;i>=;i--) sa[--cnt[rank[i]]]=i;
for (int k=;k<=n;k<<=)
{
int p=;
for (int i=n-k;i<n;i++) y[p++]=i;
for (int i=;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
for (int i=;i<m;i++) cnt[i]=;
for (int i=;i<n;i++) cnt[rank[y[i]]]++;
for (int i=;i<m;i++) cnt[i]+=cnt[i-];
for (int i=n-;i>=;i--) sa[--cnt[rank[y[i]]]]=y[i];
memcpy(y,rank,sizeof(y));
p=;rank[sa[]]=;
for (int i=;i<n;i++)
rank[sa[i]]=y[sa[i]]==y[sa[i-]] && ((sa[i]+k>=n && sa[i-]+k>=n)
|| (sa[i]+k<n && sa[i-]+k<n && y[sa[i]+k]==y[sa[i-]+k]))?p:++p;
if (p==n-) break;
m=p+;
}
}
void makeh(char* s,int* h)
{
int n=strlen(s);
h[]=s[]-'A';
for (int i=;i<n;i++)
h[i]=h[i-]*+s[i]-'A';
}
int pw[maxn];
void makepw(int n)
{
pw[]=;
for (int i=;i<=n;i++)
pw[i]=pw[i-]*;
}
bool ok(int x,int y)
{
int L=,R=min(n-x,m-y);
while (L<R)
{
if (ht[x+mid-]-ht[x-]*pw[mid]==hp[y+mid-]-hp[y-]*pw[mid]) L=mid;
else R=mid-;
}
return p[y+L]<=t[x+L];
}
int lcp(int x,int y)
{
int now=;
while (x<n && y<m && t[x]==p[y]) now++,x++,y++;
return now;
}
void play(int &x)
{
int L=,R=n;
while (L<R)
{
int mid=(L+R)>>;
if (ok(sa[mid],x)) R=mid;
else L=mid+;
}
if (!L) x+=lcp(sa[L],x);
else if (L<n) x+=max(lcp(sa[L-],x),lcp(sa[L],x));
else x+=lcp(sa[n-],x);
}
bool isalpha(char c) {return c>='A' && c<='Z';}
int main()
{
scanf("%d%d",&n,&m);
t[n]='\0';p[m]='\0';
for (int i=;i<n;i++)
{
while (!isalpha(c=getchar()));
t[i]=c;
}
for (int i=;i<m;i++)
{
while (!isalpha(c=getchar()));
p[i]=c;
}
makesa(t);
makeh(t,ht);makeh(p,hp);makepw(max(n,m));
int now=,ans=;
while (now<m) play(now),ans++;
printf("%d\n",ans);
return ;
}
BZOJ2099: [Usaco2010 Dec]Letter 恐吓信的更多相关文章
- BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机+贪心
BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机 Description FJ刚刚和邻居发生了一场可怕的争吵,他咽不下这口气,决定佚名发给他的邻居 一封脏话连篇的信. ...
- 【BZOJ】2099: [Usaco2010 Dec]Letter 恐吓信
[题意]给定长度为n和m的两个字符串S和T,要求在字符串S中取出若干段拼成T(可重复取),求最小段数,n,m<=50000. [算法]后缀自动机 || 后缀数组 [题解]对串S建SAM,然后在上 ...
- BZOJ2097[Usaco2010 Dec] 奶牛健美操
我猜我这样继续做水题会狗带 和模拟赛的题很像,贪心搞一下. #include<bits/stdc++.h> using namespace std; int read(){ ,f=;cha ...
- BZOJ2101: [Usaco2010 Dec]Treasure Chest 藏宝箱
2101: [Usaco2010 Dec]Treasure Chest 藏宝箱 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 327 Solved: ...
- BZOJ 2100: [Usaco2010 Dec]Apple Delivery( 最短路 )
跑两遍最短路就好了.. 话说这翻译2333 ---------------------------------------------------------------------- #includ ...
- BZOJ 2101: [Usaco2010 Dec]Treasure Chest 藏宝箱( dp )
dp( l , r ) = sum( l , r ) - min( dp( l + 1 , r ) , dp( l , r - 1 ) ) 被卡空间....我们可以发现 l > r 是无意义的 ...
- 2102: [Usaco2010 Dec]The Trough Game
2102: [Usaco2010 Dec]The Trough Game Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 117 Solved: 84[ ...
- BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP
BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP Description Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的 ...
- bzoj2101【Usaco2010 Dec】Treasure Chest 藏宝箱
2101: [Usaco2010 Dec]Treasure Chest 藏宝箱 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 418 Solved: ...
随机推荐
- AJPFX关于java中的方法
java中的方法和c语言中的函数类似,是新手入门面向对象之前的内容最大的难关如何写方法 1,明确返回值类型 2,明确参数列表 * 修饰符:目前就用 public stati ...
- Intro Of Myself
- vue跨域解决及打包
打包之前需要修改如下配置文件: 配置文件一:build>>>utils.js (修改publicPath:"../../" , 这样写是处理打包后找不到静态文件( ...
- 【持续更新】把.net代码转换为java代码的注意事项
国内大多数大学的软件相关专业大多强制学生学习c和Java,但.net 的几个语言可以说是选学的. 由于visual studio在windows平台上使用相对方便,一些同学会在上大学的Java课之前自 ...
- linux截图工具
推荐:deepin-scrot 满足功能: 能够自定义快捷键(Ctrl+Alt+A) 小巧快速自定义选择区域进行截图 有简单的绘图功能 可以快速的保存到剪切版(双击图片) P.S.:双重截图
- PHP CLI应用的调试原理
我们在Eclipse里选中一个PHP文件,右键选择Debug As->PHP CLI Application. 所谓CLI应用,是指这种脚本文件不需要任何Web服务器即可运行,当然, PHP运行 ...
- Windows程序设计1(工具、编码、窗口)
一.几个常用小工具: 1. 编译器:CL.EXE 将源文件转变为目标文件(汇编语言). CL.EXE /c xxx.c 或 xx.cpp cl.exe -? 显示cl帮助 cl.exe ...
- 超不清视频播放器-用Python将视频转成字符
前言 今天分享的这段代码,看起来没啥实际用处,而且有些反潮流,因为现如今大家看视频都追求更高分辨率的超清画质,而我们这个,是一个“超不清”的视频播放器:在控制台里播放视频,用字符来表示画面 不过我觉得 ...
- gcc 变量类型大小 练习 远离 cygwin64 需要带dll
/* testmini.c -- very simple test program for the miniLZO library */ #include <stdio.h> #inclu ...
- More Effective C++ - 章节二 : 操作符(operators)
5. 对定制的 "类型转换函数" 保持警觉 允许编译器执行隐式类型转换,害处多过好处,不要提供转换函数,除非你确定需要. class foo { foo(int a = 0, in ...