HDU 5558 2015ICPC合肥站G题
2015-12-09 20:33
211 查看
题意:给一个字符串加密,加密规则为:
对于第i个字符 如果存在S[T.....T+K-1] == S[i....i+K-1] 则输出T,K 如果有多种方法输出K最大的 如果有多种K最大的方法则输出T最小的。然后把i增加K
如果不存在。则输出-1 和 第i个字符的ASCII码 并且把i增加1.
解法:首先用后缀数组求出 sa rk 和 height
然后可知若rk[A]<rk[B] 那么他们的最长公公前缀为 min(height[i]) A<I<=B;
设S(A,B)为A和B的最长公公前缀;
易知 若rk[A]<rk[B]<rk[C] 则 S(A,C)<=S(B,C);
所以对于第i个字符 只需要向左右两边找出最近的并且起始点在你之前的rk即可,可用单调栈维护(我不会)于是傻逼的写了个线段树
找到之后只需要求出一段区间的最小值即可,可用树状数组优化(因为前面写了线段树,所以偷懒就用线段树了)
求出最小值之后就可以通过之前求到的两个rk向外扩展求最小的T即可
写题的时候犯了一个特别傻逼的错误 所以WA了好多发。。。。。。
对于第i个字符 如果存在S[T.....T+K-1] == S[i....i+K-1] 则输出T,K 如果有多种方法输出K最大的 如果有多种K最大的方法则输出T最小的。然后把i增加K
如果不存在。则输出-1 和 第i个字符的ASCII码 并且把i增加1.
解法:首先用后缀数组求出 sa rk 和 height
然后可知若rk[A]<rk[B] 那么他们的最长公公前缀为 min(height[i]) A<I<=B;
设S(A,B)为A和B的最长公公前缀;
易知 若rk[A]<rk[B]<rk[C] 则 S(A,C)<=S(B,C);
所以对于第i个字符 只需要向左右两边找出最近的并且起始点在你之前的rk即可,可用单调栈维护(我不会)于是傻逼的写了个线段树
找到之后只需要求出一段区间的最小值即可,可用树状数组优化(因为前面写了线段树,所以偷懒就用线段树了)
求出最小值之后就可以通过之前求到的两个rk向外扩展求最小的T即可
写题的时候犯了一个特别傻逼的错误 所以WA了好多发。。。。。。
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<iostream> using namespace std; #define rep(i,n) for(int i = 0;i < n; i++) #define CLEAR(a) memset(a,0,sizeof(a)) using namespace std; const int N =200005, INF = 1<<30; int rk ,sa ,height ,w ,wa ,res ; void getSa (int len,int up) { int *k = rk,*id = height,*r = res, *cnt = wa; rep(i,up) cnt[i] = 0; rep(i,len) cnt[k[i] = w[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) { sa[--cnt[k[i]]] = i; } int d = 1,p = 0; while(p < len){ for(int i = len - d; i < len; i++) id[p++] = i; rep(i,len) if(sa[i] >= d) id[p++] = sa[i] - d; rep(i,len) r[i] = k[id[i]]; rep(i,up) cnt[i] = 0; rep(i,len) cnt[r[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) { sa[--cnt[r[i]]] = id[i]; } swap(k,r); p = 0; k[sa[0]] = p++; rep(i,len-1) { if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]] == r[sa[i+1]]&& r[sa[i]+d] == r[sa[i+1]+d]) k[sa[i+1]] = p - 1; else k[sa[i+1]] = p++; } if(p >= len) return ; d *= 2,up = p, p = 0; } } void getHeight(int len) { rep(i,len) rk[sa[i]] = i; height[0] = 0; int ans=0; for(int i = 0,p = 0; i < len; i++) { if(rk[i]==0) continue; int j = sa[rk[i]-1]; while(i+p < len&& j+p < len&& w[i+p] == w[j+p]) { p++; } height[rk[i]] = p; //cout<<i<<" "<<rk[i]<<" "<<p<<endl; //if(i<len1-1&&j>=len1) ans=max(ans,p); //else if(i>=len1&&j<len1-1) ans=max(ans,p); p = max(0,p - 1); } //return ans; } struct tree1 { int left; int right; int maxn; int minn; }tre[400005],tre1[400005]; void init(tree1 *tree,int inst,int l,int r) { tree[inst].left=l; tree[inst].right=r; tree[inst].maxn=-INF; tree[inst].minn=INF; if(l==r) return ; int mid=(l+r)>>1; init(tree,2*inst,l,mid); init(tree,2*inst+1,mid+1,r); } void add(tree1 *tree,int inst,int k,int z) { tree[inst].maxn=max(tree[inst].maxn,z); tree[inst].minn=min(tree[inst].minn,z); if(tree[inst].left==tree[inst].right) return ; int mid=(tree[inst].left+tree[inst].right)>>1; if(mid<k) add(tree,2*inst+1,k,z); else add(tree,2*inst,k,z); } int query(tree1 *tree,int inst,int l,int r,bool flag) { if(tree[inst].left==l&&tree[inst].right==r) { if(!flag) return tree[inst].maxn; else return tree[inst].minn; } int mid=(tree[inst].left+tree[inst].right)>>1; if(r<=mid) return query(tree,2*inst,l,r,flag); else if(l>mid) return query(tree,2*inst+1,l,r,flag); else { if(!flag) return max(query(tree,2*inst,l,mid,flag),query(tree,2*inst+1,mid+1,r,flag)); else return min(query(tree,2*inst,l,mid,flag),query(tree,2*inst+1,mid+1,r,flag)); } } char s[100005]; int main() { int t; scanf("%d",&t); int cnt=0; while(t--) { scanf("%s",s); printf("Case #%d:\n",++cnt); int len=strlen(s); int maxn=0; for(int i=0;i<len;i++) { w[i]=s[i]; maxn=max(maxn,w[i]); } w[len++]=0; getSa(len,maxn+1); getHeight(len); len--; init(tre1,1,1,len); for(int i=1;i<=len;i++) { add(tre1,1,i,height[i]); } init(tre,1,1,len); int i=0; while(i<len) { int k=rk[i]; int l=query(tre,1,1,k,0); int r=query(tre,1,k,len,1); int res=0; int l1=-1,r1=-1; if(l!=-INF) { l1=query(tre1,1,l+1,k,1); } if(r!=INF) { r1=query(tre1,1,k+1,r,1); } res=max(res,max(l1,r1)); if(res==0) { printf("-1 %d\n",s[i]); add(tre,1,k,k); i++; } else { int T=len; if(res==l1) { T=min(sa[l],T); while(l>0&&height[l]>=res) { l--; T=min(T,sa[l]); } } if(res==r1) { T=min(T,sa[r]); while(r<=len&&height[r]>=res) { T=min(T,sa[r]); r++; } } printf("%d %d\n",res,T); while(res--) { add(tre,1,k,k); i++; k=rk[i]; } } } } }
相关文章推荐
- (学习)C Primer Plus(1)
- jQuery形式可以计算,它包含了无线电的变化价格,select价格变化,删除行动态计算加盟
- map 容器小例(hash map)
- Android 读取txt文件并以utf-8格式转换成字符串
- 动态规划 - 最长递增子序列(LIS)
- JPA(7) spring-data-jpa
- STL源码剖析之vector
- 升级oralce linux从7.1到7.2
- poj1823线段树
- 最小次数(递归)
- 枚举中关于toRaw()和fromRaw(3)编译出错
- UVALive 7279 Sheldon Numbers(位运算、暴力、想法)
- Codeforces 420 B. Online Meeting
- leetcode Path Sum II
- Android 读取txt文件并以utf-8格式转换成字符串
- 欢迎使用CSDN-markdown编辑器
- POJ 3252 Round Numbersm
- ubuntu下gerrit 安装部署
- sap JCO3.0安装缺少Microsoft Visual C++ 2005 Service Pack 1 Redistributable Package (KB973544)
- 106 Construct Binary Tree from Inorder and Postorder Traversal