[noip测试]拯救紫萱学姐(kmp+树形dp)
2016-11-07 12:43
148 查看
时间限制:1 s 内存限制:256 MB
由于明天要考试,同学们要把抽屉里的书都搬空,书很多而且办了走读不能回寝室的学长一眼就看到了回班撩他的学姐,于是就把学姐当学长用♂了:“帮我把这摞书搬走OvO”。
学姐筋疲力尽地抱着沉重的一摞书回到了机房,出于无聊她翻开了学长的字典。
学长的字典由一个字符串组成。对于两个字符串a和b,如果a既是b的前缀也是b的后缀,那么称a和b“相似”,空字符串和任何字符串相似。一个字符串可以通过编辑变换成一个比它短而且与它相似的字符串,付出的代价为这两个字符串的长度之差的平方。两个字符串通过编辑而变为同一个字符串所花费的最小代价被称为最短编辑距离。
给定学长的字典,现在学姐想知道这个字符串的每一对前缀的最短编辑距离中的最大值是多少。请你帮助劳累的紫萱学姐解决这个问题。
【输入格式】
一个字符串,仅包含小写英文字母。
【输出格式】
这个字符串每一对前缀中最长的最短编辑距离。
【样例输入】
abcab
【样例输出】
23
【提示】
最短编辑距离最长的一对前缀是abca和abcab,最短变换过程如下(箭头中的数字为过程的代价)
“abca”-9->“a”-1->(空字符串)
“abcab”-9->“ab”-4->“”
对于40%的数据,n≤500。
对于70%的数据,n≤5000。
对于100%的数据,n≤1000000,n为字符串长度。
首先考虑暴力怎么做。由于是计算平方值,对于两个固定的串,肯定是把每一步分得越小越好。也就是说,每一个串都和它的失配有关。
考虑以i结尾和以j结尾的前缀,每次都暴力地将这两个点蹦到离当前点比较近的失配,然后从那个失配的答案转移。实际上是一个暴力dp,时间复杂度O(n2∗2logn)。
考虑怎么将这个算法优化。可以发现,每一个点有可能向其后面的点转移,但是它只会由它的失配转移过来。这样实际上就是构成了一个树结构,树的边权就是点数的平方。这样的话,由于是求两个不同的前缀的答案,其实就是求树上不同的两个点距离的最大值,即为树的直径。时间复杂度O(n2)。
考试的时候有一些奇怪的思路,比如连边之后跑最长路。但是最长路是多源的发现并不能搞定。其实这个树的模型还是比较显然的。
题目描述
其实在开考前半个小时题面并不是这样的。由于明天要考试,同学们要把抽屉里的书都搬空,书很多而且办了走读不能回寝室的学长一眼就看到了回班撩他的学姐,于是就把学姐当学长用♂了:“帮我把这摞书搬走OvO”。
学姐筋疲力尽地抱着沉重的一摞书回到了机房,出于无聊她翻开了学长的字典。
学长的字典由一个字符串组成。对于两个字符串a和b,如果a既是b的前缀也是b的后缀,那么称a和b“相似”,空字符串和任何字符串相似。一个字符串可以通过编辑变换成一个比它短而且与它相似的字符串,付出的代价为这两个字符串的长度之差的平方。两个字符串通过编辑而变为同一个字符串所花费的最小代价被称为最短编辑距离。
给定学长的字典,现在学姐想知道这个字符串的每一对前缀的最短编辑距离中的最大值是多少。请你帮助劳累的紫萱学姐解决这个问题。
【输入格式】
一个字符串,仅包含小写英文字母。
【输出格式】
这个字符串每一对前缀中最长的最短编辑距离。
【样例输入】
abcab
【样例输出】
23
【提示】
最短编辑距离最长的一对前缀是abca和abcab,最短变换过程如下(箭头中的数字为过程的代价)
“abca”-9->“a”-1->(空字符串)
“abcab”-9->“ab”-4->“”
对于40%的数据,n≤500。
对于70%的数据,n≤5000。
对于100%的数据,n≤1000000,n为字符串长度。
题解
比较好的一道思路题。首先考虑暴力怎么做。由于是计算平方值,对于两个固定的串,肯定是把每一步分得越小越好。也就是说,每一个串都和它的失配有关。
考虑以i结尾和以j结尾的前缀,每次都暴力地将这两个点蹦到离当前点比较近的失配,然后从那个失配的答案转移。实际上是一个暴力dp,时间复杂度O(n2∗2logn)。
考虑怎么将这个算法优化。可以发现,每一个点有可能向其后面的点转移,但是它只会由它的失配转移过来。这样实际上就是构成了一个树结构,树的边权就是点数的平方。这样的话,由于是求两个不同的前缀的答案,其实就是求树上不同的两个点距离的最大值,即为树的直径。时间复杂度O(n2)。
考试的时候有一些奇怪的思路,比如连边之后跑最长路。但是最长路是多源的发现并不能搞定。其实这个树的模型还是比较显然的。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 1000005 #define LL long long int n; char s ; int T ; int tot,point ,nxt[N*2],v[N*2];LL c[N*2]; LL f ,g ,ans; void calc() { T[0]=-1; int j; for (int i=0;i<n;++i) { j=T[i]; while (j!=-1&&s[j]!=s[i]) j=T[j]; T[i+1]=++j; } } void add(int x,int y,LL z) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z; } void treedp(int x,int fa) { for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { treedp(v[i],x); if (f[v[i]]+c[i]>f[x]) { g[x]=f[x]; f[x]=f[v[i]]+c[i]; } else g[x]=max(g[x],f[v[i]]+c[i]); } ans=max(ans,f[x]+g[x]); } int main() { freopen("savemzx.in","r",stdin); freopen("savemzx.out","w",stdout); gets(s);n=strlen(s); calc(); for (int i=1;i<=n;++i) add(T[i],i,((LL)i-(LL)T[i])*((LL)i-(LL)T[i])); treedp(0,-1); printf("%I64d\n",ans); }
总结
①分析能力和建模能力还是有点弱啊。以后一定要多抽象,多联系。相关文章推荐
- 【NOIP 模拟题】[T2]拯救紫萱学姐(kmp+树形dp)
- test 拯救紫萱学姐 (kmp+树的直径)
- 【NOIP 模拟题】[T2]宝藏(树形dp)
- [CODEVS1090][NOIP2013]加分二叉树(树形dp)
- (noip 模拟 染色)<树形DP>
- 【NOIP2016练习】T3 tree (树形DP)
- 【NOIP2016练习】T2 花花的聚会 (树形DP,倍增)
- NOIP模拟题 2016.10.18 [二分答案] [从上到下的树形DP] [链表翻转]
- NOIP模拟 10.17 单调队列 + 树形Dp + 区间Dp
- 【NOIP2014八校联考第1场第1试9.20】统计损失(count)(树形dp)
- 树形dp(人品问题NOIP17提高模拟训练3)
- NOIP模拟 探险 【树形dp】
- 【树形DP】[NOIP2003]加分二叉树
- 【学姐的胡策】训练8.18(KMP+dp)
- 【loli的胡策】NOIP训练10.2(快速幂+树形期望dp)
- 【loli的胡策】NOIP训练8.10(数论+树形dp+贪心)
- NOIP2011pj表达式的值[树形DP 笛卡尔树 | 栈 表达式解析]
- NOIP模拟题 2016.9.3 [数论] [逆序对] [树状数组] [树形dp]
- [noip测试]最长上升子串(乱搞||dp)
- (vijos 1892 noip 模拟 tree)<树形DP求树的最大匹配及方案数>