字符串的最小表示法[hdu5442]
来源:互联网 发布:网络工程师和程序员 编辑:程序博客网 时间:2024/05/15 02:06
题目描述
Lulu has a sweet tooth. Her favorite food is ring donut. Everyday she buys a ring donut from the same bakery. A ring donut is consists of n parts. Every part has its own sugariness that can be expressed by a letter from a to z (from low to high), and a ring donut can be expressed by a string whose i-th character represents the sugariness of the i−th part in clockwise order. Note that z is the sweetest, and two parts are equally sweet if they have the same sugariness.
Once Lulu eats a part of the donut, she must continue to eat its uneaten adjacent part until all parts are eaten. Therefore, she has to eat either clockwise or counter-clockwise after her first bite, and there are 2n ways to eat the ring donut of n parts. For example, Lulu has 6 ways to eat a ring donut abc: abc,bca,cab,acb,bac,cba. Lulu likes eating the sweetest part first, so she actually prefer the way of the greatest lexicographic order. If there are two or more lexicographic maxima, then she will prefer the way whose starting part has the minimum index in clockwise order. If two ways start at the same part, then she will prefer eating the donut in clockwise order. Please compute the way to eat the donut she likes most.
算法思路
- 这一题的题目还是十分明确的,就是求一个字符串的最小的循环子串。
- 看过OI集训队周源的一篇论文,我们要求的是这个字符串的一个最大的表示,可以使用下面的算法来完成
3.算法的具体思路:
(1)开始时,将字符串复制两份,设置两个指针,i=0,j=1.
(2)k=0,然后反复迭代直到s[i+k]!=s[j+k]
(3)如果k=n,那么返回较小的值,否则看情况滑动指针
4.算法正确性的证明
(1)算法返回的一定是字典序最大的那个循环子串
首先我们设存在一个子串比返回的串更大,而由我们的算法的迭代,我们知道|i−j|<n , 为了方便,我们设i<j ,则我们知道存在一个位置t,使得str[i]<str[t] ,并且str[t]=max(str[i−t]) , 则我们知道j一定会滑动到这个位置。因为从i-t没有一个字符可以和str[t]匹配。
(2)在找到循环节的时候,最小循环字符串的起始地址一定是n−len+min(i,j),len=abs(i−j)
证明:当我们在循环中找到一个循环节的时候,根据上面的性质,我们知道这个时候i,j都是指向了最大的那个字符,那么我们要做的就是根据这个循环节找到这个最大的字符最后出现的位置。很显然,我们知道这个位置一定会在[n−len,n−1] 当中,但是这个位置究竟在哪里呢?
很显然,我们所要的值就在min(i,j)的位置,这个值也一定小于len,因为如果这个字符找到第一个循环节中的最大的字符的时候,就不会存在其他的字符能够使得这个指针再次滑动了。所以,我们的结论就可以得到证明了。
代码
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define MAXN 40005int n,t;char clockwise[MAXN],anticlockwise[MAXN];int processa(char* s){//cal the min index int i=0,j=1,k; while(i<n&&j<n){ k = 0; while(s[i+k]==s[j+k]&&k<n)k++; if(k==n)return min(i,j); if(s[i+k]>s[j+k]){ if(j+k+1>i) j = j+k+1; else j = i+1; } else{ if(i+k+1>j) i = i+k+1; else i = j+1; } } return min(i,j);}int processb(char* s){//calulate the max index int i=0,j=1,k; while(i<n&&j<n){ k = 0; while(s[i+k]==s[j+k]&&k<n)k++; if(k==n){ int len = abs(i-j); return n-len+min(i,j); } if(s[i+k]>s[j+k]){ if(j+k+1>i) j = j+k+1; else j = i+1; } else{ if(i+k+1>j) i = i+k+1; else i = j+1; } } if(j>=n)return i; else return j;}int main(){ freopen("input","r",stdin); int i; scanf("%d",&t); while(t--){ scanf("%d",&n); scanf("%s",clockwise); for(i=0;i<n;i++){ clockwise[n+i]=clockwise[i]; } clockwise[2*n] = '\0'; for(i=0;i<2*n;i++) anticlockwise[i] = clockwise[2*n-i-1]; int ans1 = processa(clockwise); int ans2 = processb(anticlockwise); //printf("%d %d\n",ans1,ans2); int l = strncmp(clockwise+ans1,anticlockwise+ans2,n); if(l==0){ if(n-ans2<ans1+1) printf("%d 1\n",n-ans2); else printf("%d 0\n",ans1+1); } else if(l>0) printf("%d 0\n",ans1+1); else printf("%d 1\n",n-ans2); } return 0;}
- 字符串的最小表示法[hdu5442]
- hdu5442 最小最大表示法+kmp
- HDU5442 最小(大)表示法
- hdu5442-字符串循环节&最小表示法|后缀数组(未补)|kmp+最小-Favorite Donut
- 【HDU5442 2015长春网络赛F】字符串最小表示法+函数逆用循环节法+翻转串字符串哈希法
- 字符串的最小表示法
- 字符串的最小表示法
- 字符串的最小表示法
- 字符串的最小表示
- 字符串最小表示法
- 字符串最小表示法
- 字符串的最小表示法及实现
- 【字符串循环同构的最小表示法】
- la2755 字符串的最小表示法
- 循环字符串的最小表示法
- 字符串的最小/最大表示法
- hdu2609 字符串的最小表示法模版
- 字符串的最大最小表示法 模板
- 一些小函数集锦
- jQuery插件开发的五种形态小结
- 网络爬虫学习笔记之概述
- [spring,mysql] spring使用注解式事务声明(@Transactional)无法回滚
- Git常见用法
- 字符串的最小表示法[hdu5442]
- 【笔记】Python 3自学笔记之函数
- 【计算机】DOS命令
- Java笔记 - 多态
- Git学习笔记(二)
- 常用的几种单元测试
- c语言关键字
- POJ 1679 The Unique MST 最小代价生成树 次小代价生成树
- Android中的Adapter 详解(四)