真是一道好题喵~

果然自动机什么的就是要和 dp 搞基才是王道有木有!

A:连 CTSC 都叫我们搞基,果然身为一个程序猿,加入 FFF 团是我此生最明智的选择。妹子什么闪边去,大家一起来搞基吧!

Q:教练你是什么时候产生了 dp 和自动机是同性的错觉~ 教练你又是什么时候产生了你还有个不入团的选择 ( 妹 子 )这样的错觉~

A:显而易见的,我们……

Q:教练不要转移话题啊!

A:显而易见的,我们先搞一个后缀自动机……

Q:等等,教练,多串的自动机要怎么写?

A:把几个串并在一起不就好了?

Q:不对啊,那查询的时候万一查到两个串相连的地方,不是悲剧了?

A:你傻啊!搞个分割符什么的不就解决了?!

Q:教练我的分割符是用 $ 还是用 # 呢?

(旁白:当然是 $ 了,$ 可是美金的意思,# 算什么,电话号码吗?)

A:。。。。。。

搞出了后缀自动机,就像我们经常做的一样,把每个节点能匹配的最长长度搞出来    (Q:我没文化你也不能这么逗我!)

把字串 S 在第 i 位能匹配到的最长长度 same[i] 搞出来

考虑二分答案L

就有了个显而易见的 dp 转移方程:

f[i]=max{f[j]-j+i | i-same[i]<=j<=i-L}

然后题目就被妥妥的解决了

Q:不对啊教练,这 dp 是 O(n2) 的!

f[i]=max{f[j]-j+i | i-same[i]<=j<=i-L}  ↔  f[i]-i=max{f[j]-j | i-same[i]<=j<=i-L}

A:这显然是单调的,优化优化就 O(n) 了

Q:教练求证明……

A:这个显然嘛,显然……要不然这题还怎么做额?

Q:教练……

A:烦死了,你打个表不就行了!

 #include <cstdio>
#include <cstring>
#include <cmath>
const int sizeOfType=;
const int sizeOfString=;
const int sizeOfMemory=; inline void getstring(char * s)
{
register char ch;
register int top=;
do ch=getchar(); while (ch<'' || ch>'');
do s[top++]=ch, ch=getchar(); while (ch>='' && ch<='');
s[top]='\0';
} struct deque
{
int l, r;
int q[sizeOfString];
inline deque():l(), r(-) {}
inline void clear() {l=, r=-;}
inline bool empty() {return l>r;}
inline int front() {return q[l];}
inline int back() {return q[r];}
inline void push(int x) {q[++r]=x;}
inline void pop_front() {++l;}
inline void pop_back() {r--;}
}; int N, M;
int len;
int same[sizeOfString];
char str[sizeOfString];
deque q;
int f[sizeOfString], g[sizeOfString];
inline int max(int x, int y) {return x>y?x:y;}
inline void dp(int); namespace suffixAutomaton
{
struct node
{
int step;
node * fail;
node * ch[sizeOfType];
};
node memory[sizeOfMemory], * port=memory;
node * dfa, * last;
inline node * newnode(node * t=NULL)
{
node * newt=port++;
newt->step=;
if (t) newt->fail=t->fail, t->fail=newt, memcpy(newt->ch, t->ch, sizeof t->ch);
else newt->fail=NULL, memset(newt->ch, , sizeof newt->ch);
return newt;
}
inline void clear() {port=memory; dfa=newnode(); dfa->fail=dfa; last=dfa;} inline int ord(char ch) {return ch>=''?ch-'':;}
inline void insert(int w)
{
node * p=last, * newp=newnode();
newp->step=p->step+; for ( ;p->ch[w]==NULL;p=p->fail) p->ch[w]=newp;
if (p->ch[w]==newp)
newp->fail=dfa;
else
{
node * q=p->ch[w];
if (q->step==p->step+)
newp->fail=q;
else
{
node * newq=newnode(q);
newq->step=p->step+;
newp->fail=newq;
for ( ;p->ch[w]==q;p=p->fail) p->ch[w]=newq;
}
} last=newp;
}
inline void buildDfa()
{
static char s[sizeOfString];
int len; clear();
for (int i=;i<M;i++)
{
getstring(s); len=strlen(s);
for (int j=;j<len;j++)
insert(ord(s[j]));
insert(ord('$'));
}
}
inline void search(char * s)
{
int tot=;
node * t=dfa; for (int i=;i<=len;i++)
{
int w=ord(s[i-]);
if (t->ch[w])
{
t=t->ch[w];
++tot;
}
else
{
node * j;
for (j=t->fail;j!=dfa && !j->ch[w];j=j->fail);
if (j->ch[w])
{
t=j->ch[w];
tot=j->step+;
}
else
{
t=dfa;
tot=;
}
}
same[i]=tot;
}
}
} int main()
{
scanf("%d %d", &N, &M);
suffixAutomaton::buildDfa();
for (int i=;i<=N;i++)
{
getstring(str);
len=strlen(str);
suffixAutomaton::search(str); int L=, R=len+;
while (L+<R)
{
int M=(L+R)>>;
dp(M);
if (*f[len]>=*len) L=M;
else R=M;
} printf("%d\n", L);
} return ;
}
inline void dp(int L)
{
q.clear(); for (int i=;i<=len;i++)
{
int j=i-L;
if (j>=)
{
for ( ;!q.empty() && g[j]>g[q.back()];q.pop_back());
q.push(j);
}
f[i]=f[i-];
for ( ;!q.empty() && q.front()<i-same[i];q.pop_front());
if (!q.empty())
f[i]=max(f[i], g[q.front()]+i);
g[i]=f[i]-i;
}
}

本傻乱搞系列

后记:

话说我根本不知道如何证明单调性,但是大家注意到这是类似于一个一直在往右移动的窗口(不要问我为什么 i-same[i] 是单增的,事实如此)

移动的窗口,求窗口中最大的数……很眼熟啊!经验和直觉都告诉我们这就是单调队列……

大家理性理解一下就好,就好~

[CTSC 2012][BZOJ 2806]Cheat的更多相关文章

  1. BZOJ 2806 cheat

    首先这个题目显然是要二分转换成判断可行性的 之后我们考虑DP 设f(i)表示 1->i 熟悉的子串的长度的最大值 那么对于i这个点,要么不在熟悉的子串中,要么在熟悉的子串中 所以得到 f(i)= ...

  2. 后缀自动机SAM BZOJ 2806

    终于遇到了一道后缀数组不能过 一定要学SAM的题... (看了半个下午+半个上午) 现在总结一下(是给我自己总结..所以只总结了我觉得重要的 .. 看不太懂的话可以To   http://blog.c ...

  3. bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 583  Solved: 330[Submit][Statu ...

  4. BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]

    2806: [Ctsc2012]Cheat 题意: 多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的 如果熟悉的字符串长度>=询问串 ...

  5. 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description ...

  6. BZOJ 2806 Luogu P4022 [CTSC2012]Cheat (广义后缀自动机、DP、二分、单调队列)

    题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=2806 (luogu) https://www.luogu.org/pro ...

  7. bzoj 2806: [Ctsc2012]Cheat

    传送门 好久没刷bzoj惹…… 题意不说可以嘛. 首先二分答案. SAM的事情搞完以后就是dp辣. 我们已经对于每个位置i,找到了最小的一个k,使得[k,i]这个子串在模版串中出现过.那么我们需要做的 ...

  8. bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806 只想着怎么用后缀数据结构做,其实应该考虑结合其他算法. 可以二分那个长度 L .设当前 ...

  9. BZOJ 2806 【CTSC2012】 Cheat

    题目链接:Cheat 话说这道题很久以前某人就给我们考过,直到现在,我终于把这个坑填上了…… 这道题要我们把一个串\(S\)划分成若干块,每块长度不小于\(L_0\),使得能够在文章库中完全匹配的块的 ...

随机推荐

  1. SharePoint 2016 的新特性概览(二)(What's New for IT Professionals in SharePoint Server 2016)

    博客地址:http://blog.csdn.net/FoxDave SharePoint 2016 的新特性 三. 监测和数据(Insights and Data) 实时数据监测,包括对使用情况.存储 ...

  2. SQL Server 2005使用作业设置定时任务(转)

    1.开启SQL Server Agent服务 使用作业需要SQL Agent服务的支持,并且需要设置为自动启动,否则你的作业不会被执行. 以下步骤开启服务:开始-->>>运行--&g ...

  3. 加载不同的nib文件

    只需要实现nibName方法即可 另外还需在vc控制器初始化的时候不指定对应的nib文件名 -(NSString *)nibName { if(UI_USER_INTERFACE_IDIOM() == ...

  4. 转 如何用mt7620方案的rt2860v2驱动实现wifi探针功能,网上能搜到一些方法,但是讲的好模糊?

    原文:http://www.zhihu.com/question/33559283 如何用mt7620方案的rt2860v2驱动实现wifi探针功能,网上能搜到一些方法,但是讲的好模糊? 如何用mt7 ...

  5. LeetCode222 Count Complete Tree Nodes

    对于一般的二叉树,统计节点数目遍历一遍就可以了,但是这样时间复杂度O(n),一下就被卡住了. 这题首先要明白的是,我们只需要知道叶子节点的数目就能统计出总节点树. 想法1: 既然是完全二叉树,我肯定是 ...

  6. vim的Tab设置为4个空格

    vim /etc/vimrc 1    set ts=42    set expandtab3    set autoindent 按tab键时产生的是4个空格,这种方式具有最好的兼容性.

  7. 有意义的命名 Meaningful names

    名副其实 use intention-revealing names 变量.函数或类的名称应该已经答复了所有的大问题.它该告诉你,他为什么会存在,他做什么事,应该怎么用.我们应该选择都是致命了计量对象 ...

  8. Redis - 常用命令操作

    常用命令keys:        keys *        查看符合条件的所有key exists:        exists key    查看key是否存在 del:        del k ...

  9. Sticky Footer (让页脚永远停靠在页面底部,而不是根据绝对位置)

    <!doctype html><html> <head> <meta charset="UTF-8"> <meta name= ...

  10. iOS-代理

    1.协议是一组通讯协议,一般用作两个类之间的通信. 2.协议声明了一组所有类对象都可以实现的接口. 3.协议不是类,用@protocol关键字声明一个协议. 4.与协议有关的两个对象,代理者和委托者. ...