您的位置:首页 > 其它

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了好多发。。。。。。
#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];
}
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: