http://www.spoj.com/problems/COMPRESS/
题目简述
定义字符串的压缩表示[S]N,它等价于N 个S 串从左向右依次连接起来的新串。压缩表示可以嵌套,即S 本身可以是压缩过的字符串。
如“[a]2”代表“aa”,“[[ab]2c]2”代表“ababcababc”。
给出两个压缩以后的字符串S1 和S2,判断它们在哪一位开始不相同。
对于每组字符串,如果S1 和S2 完全相同,输出“Yes”,否则输出“NO”+它们第一个不相同的位置。
Sample Input
5
a[a]12
[[a]3]4a
[z]12
zzzzzzzzz
[a[ba]2b]12
[ab]36
[a]123123123[icpc]2
[[a]123]1001001inter
aismoreeasierthanc
gismuchharderthanj
Sample Output
Case #1: YES
Case #2: NO 10
Case #3: YES
Case #4: NO 123123125
Case #5: NO 1
神级恶心题。。鼓捣了一个上午才搞出来。。
先说一下暴力解压吧。
可以递归做,每个括号递归一次。
先上个暴力代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
#define rep(i,l,r) for (int i=l;i<=r;++i)
string a;
int getx(int &x,int v){
for (x=0;a[v]>='0'&&a[v]<='9';v++)
x=(x<<3)+(x<<1)+a[v]-'0';
return v;
}
string zip(int l,int r,int p){
string res="";
rep(i,l,r){
if (a[i]>='a'&&a[i]<='z') res+=a[i];
if (a[i]=='['){
int cnt=1;
rep(j,i+1,r){
if (a[j]=='[') cnt++;
if (a[j]==']') cnt--;
if (!cnt){
int tp;
int pos=getx(tp,j+1)-1;
if (tp!=0) res+=zip(i+1,j-1,tp);
i=pos;
break;
}
}
}
}
string tp="";
rep(i,1,p) tp+=res;
return tp;
}
string t1,t2;
int main(){
freopen("compress.in","r",stdin);
freopen("compress.out","w",stdout);
int T;scanf("%d",&T);
while (T--){
cin>>a;
t1=zip(0,a.length()-1,1);
t1+='*';
cin>>a;
t2=zip(0,a.length()-1,1);
t2+='*';
bool pd=false;
rep(i,0,t1.length()-1)
if (t1[i]!=t2[i]){pd=true;printf("%d\n",i+1);break;}
if (!pd) printf("Yes\n");
}
}
标算:二分+哈希。压缩串用二叉树装。
基本思路:二分位置,用哈希判断前缀是否同。
现在问题就是如何算一个前缀的哈希。
和上面暴力解压的方法类似,递归建树,但是不保留串,只保留子树串的哈希值。
我写的有点麻烦。。。不说了。。
算哈希要运用的式子:
令Hash(x)表示串x的哈希值。Hash(x*a)表示具有连续a个x的串的哈希值。Hash(x+y)表示串xy拼接起来的哈希值。|x|表示x的串长。
当然都是MOD mod意义下的运算。。mod最好是个质数,要不然第二个式子不好算。
上面的分母算一个逆元
。。。好恶心啊真的此题爽啊,,上代码。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
using namespace std;
typedef long long LL;
const int MAX_L=25;
const LL MOD=1000000007LL;
const LL base=127LL;
LL power(LL a,LL b){
LL res=1;b%=MOD-1;
for (;b;a=a*a%MOD,b>>=1)
if (b&1) res=res*a%MOD;
return res;
}
struct Hash{
LL hash,len;
Hash(LL _h = 0 ,LL _l = 0):hash(_h),len(_l){}
void pt(){printf("%I64d %I64d\n",hash,len);}
};
bool operator ==(const Hash &a,const Hash &b){
return a.hash==b.hash&&a.len==b.len;
}
Hash operator +(const Hash &a,const Hash &b){
return Hash((a.hash*power(base,b.len)+b.hash)%MOD,a.len+b.len);
}
Hash operator *(const Hash &a,LL b){
return Hash(((a.hash*(power(base,a.len*b)-1+MOD))%MOD*power(power(base,a.len)-1+MOD,MOD-2))%MOD,a.len*b);
}
Hash gt(const char *s){
Hash res;
res.len=strlen(s);
rep(i,0,res.len-1) res.hash=res.hash*base%MOD+s[i];
return res;
}
struct Tree{
char s[MAX_L];
int lc[MAX_L*100],rc[MAX_L*100];
int n,root,tal;
LL w[MAX_L*100];
Hash h[MAX_L*100];
void set(int &x,int _tal,LL _w){x=_tal;w[x]=_w;lc[x]=rc[x]=0;}
void init(){
tal=1;set(root,tal,1);
scanf("%s",s+1);
build(root,1,n=strlen(s+1));
}
int findr(int l){
int cnt=1;
rep(i,l+1,n){
if (s[i]=='[') cnt++;
if (s[i]==']') cnt--;
if (!cnt) return i;
}
}
int getn(LL &x,int l){
for (x=0;s[l]>='0'&&s[l]<='9';l++)
x=(x<<3)+(x<<1)+s[l]-'0';
return l;
}
Hash gtpre(int v,LL l){
if (l==1&&h[v].len==1) return h[v];
if (l==0) return Hash(0,0);
if (l>h[lc[v]].len*w[lc[v]]) return h[lc[v]]*w[lc[v]]+gtpre(rc[v],l-w[lc[v]]*h[lc[v]].len);
else return h[lc[v]]*(l/h[lc[v]].len)+gtpre(lc[v],l%h[lc[v]].len);
}
void build(int &v,int l,int r){
if (l>r) {w[v]=0;return;}
if (l==r){
h[v]=Hash(s[l],1);
return;
}
if (s[l]=='['){
int p1=findr(l),p2;LL x;
p2=getn(x,p1+1);
if (x!=0){
set(lc[v],++tal,x);
build(lc[v],l+1,p1-1);
}
set(rc[v],++tal,1);
build(rc[v],p2,r);
}else{
set(lc[v],++tal,1);
build(lc[v],l,l);
set(rc[v],++tal,1);
build(rc[v],l+1,r);
}
h[v]=h[lc[v]]*w[lc[v]]+h[rc[v]]*w[rc[v]];
}
};
Tree t1,t2;
bool check(LL mid){
return t1.gtpre(1,mid)==t2.gtpre(1,mid);
}
void solve(){
if (t1.h[1]==t2.h[1]){printf("YES\n");return;}
LL l=1,r=std::min(t1.h[1].len,t2.h[1].len);
if (check(r)){printf("NO %lld\n",r+1);return;}
if (!check(l)){printf("NO 1\n");return;}
while(r-l>1){
LL mid=l+r>>1;
if (check(mid)) l=mid;
else r=mid;
}
printf("NO %lld\n",r);
}
int main(){
freopen("compress.in","r",stdin);
freopen("compress.out","w",stdout);
int T;scanf("%d",&T);
rep(i,1,T){
t1.init(),t2.init();
printf("Case #%d: ",i);solve();
}
}