HDU 5442 Favorite Donut (2015年长春赛区网络赛F题)
来源:互联网 发布:成捷迅概预算软件 编辑:程序博客网 时间:2024/06/04 18:42
1.题目描述:点击打开链接
2.解题思路:本题利用后缀数组解决。这是我第一次用后缀数组解题,没想到第二发就过了,非常激动人心啊~。本题实际上就是SA的基本应用,首先求出原始串的SA,那么SA的最后一个后缀一定是顺时针方向上的最优解。这点不难证明,因为字典序比较时候,一定是从前往后比较的,这样,即使看做环形的字符串,这个大小关系依然不变,因此可以快速得到顺时针时候的答案。至于逆时针,这就需要借助一下height数组了,如果height[k]==n-sa[k-1]即LCP总是和前一个串是相同的,那么k--。为什么要这么做呢?因为假设LCP和sa[k-1]不相等,那么最优解就是sa[k],否则,因为根据题意描述,答案应该是下标较小的那个,即为翻转后的串中下标较大的那个。不难得知,下标较大的串一定是排名靠前的,所以要k--。
这样,正方向和反方向都得到答案后,再比较2个方向时候的字典序大小,即可确定最终的答案。
3.代码:
#include<iostream>#include<algorithm>#include<cassert>#include<string>#include<sstream>#include<set>#include<bitset>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cctype>#include<complex>#include<functional>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define me(s) memset(s,0,sizeof(s))#define rep(i,n) for(int i=0;i<(n);i++)typedef long long ll;typedef unsigned int uint;typedef unsigned long long ull;typedef pair <int, int> P;const int N=20000+10;struct SuffixArray{ int s[N]; int sa[N]; int rank[N]; int height[N]; int t[N],t2[N],c[N]; int n; void clear(){n=0;me(sa);} void build_sa(int m) { int i,*x=t,*y=t2; for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[i]=s[i]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(i=n-k;i<n;i++)y[p++]=i; for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[y[i]]]++; for(i=0;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break; m=p; } } void build_height() { int i,k=0; for(i=0;i<n;i++)rank[sa[i]]=i; for(i=0;i<n;i++) { if(k)k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } }};SuffixArray sa;char word[N],rev[N];int p0,p1;int n;int cmp(char*s,char*t,int p,int q)//比较正串和反串的字典序大小{ for(int i=0;i<n;i++) if(s[(p+i)%n]!=t[(q+i)%n]) return s[(p+i)%n]>t[(q+i)%n]; return 2; //相等}void solve(int dir){ if(!dir) { sa.clear(); for(int i=0;i<n;i++) sa.s[sa.n++]=word[i]-'a'+1; sa.s[sa.n++]=0; sa.build_sa(30); p0=sa.sa[sa.n-1]; } else { sa.clear(); for(int i=0;i<n;i++) sa.s[sa.n++]=rev[i]-'a'+1; sa.s[sa.n++]=0; sa.build_sa(30); sa.build_height();//求反串的最大字典序位置时候需要借助height数组 int k=sa.n-1; while(k>=1&&sa.height[k]&&sa.height[k]==n-sa.sa[k-1])k--; //LCP和k-1处的串长相等时候往前移动 p1=sa.sa[k]; }}int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d",&n); scanf("%s",word); for(int i=0;i<n;i++) rev[i]=word[n-1-i]; solve(0); solve(1); int ans,dir; int d=cmp(word,rev,p0,p1); if(d==2) { if(p0<=n-1-p1)ans=p0,dir=0; //反串中的p1在正串中的下标是n-1-p1 else ans=n-1-p1,dir=1; } else if(d>0)ans=p0,dir=0; else ans=n-1-p1,dir=1; printf("%d %d\n",ans+1,dir); }}
0 0
- HDU 5442 Favorite Donut (2015年长春赛区网络赛F题)
- HDU 5442 Favorite Donut
- HDU 5442 Favorite Donut
- HDU 5446 Unknown Treasure (2015年长春赛区网络赛J题)
- HDU 5441 Travel (2015年长春赛区网络赛E题)
- HDU 5438 Ponds (2015年长春赛区网络赛B题)
- HDU 5437 Alisha’s Party (2015年长春赛区网络赛A题)
- HDU 5445 Food Problem (2015年长春赛区网络赛I题)
- HDU 5439 Aggregated Counting (2015年长春赛区网络赛C题)
- HDU 5447 Good Numbers (2015年长春赛区网络赛K题)
- hdu 5442 Favorite Donut 最小表示法+KMP 2015长春网络赛
- HDU 5442 Favorite Donut(最大表示法 + KMP 2015长春网络赛)
- hdu 5442 长春区域赛网络赛 1006 Favorite Donut(后缀数组)
- hdu 5442 F - Favorite Donut 后缀数组 / 字符串の最小表示法+kmp
- HDU 5442 Favorite Donut 后缀数组
- HDU 5442 Favorite Donut(后缀数组)
- hdu 5442 Favorite Donut(后缀数组)
- HDU 5442 Favorite Donut(后缀数组)
- 对《Java初体验》中代码的再探究
- HDU 5438 Ponds(2015ACM长春网络赛+枚举删点+DFS求联通块)
- JAVA String 不可变对象
- 第3周项目1顺序表的基本运算
- STM32点阵
- HDU 5442 Favorite Donut (2015年长春赛区网络赛F题)
- 修改ubuntu终端里面那个提示符
- Oracle数据库安装成功后,忘记解锁账户和设置密码
- noip2006 明明的随机数 (模拟)
- 辛星收集整理之twig的常见用法
- Target-Action
- BZOJ 1124 [POI2008]枪战Maf 贪心+乱搞
- 产生死锁的原因
- android HttpClient的使用