题解 P6739 【[BalticOI 2014 Day1] Three Friends】
由于本蒟蒻太菜,想不到别的做法,所以看到题的第一反应是hash; 虽然hash确实在码量上比较多,但是它好写思维难度比较低;
分析
假设一个字符串的前缀哈希值记为 h[i],进制为 base,那么显然 h[i] = h[i-1] \times base + s[i].
记 p[i] 为 base 的 i 次方,那么我们可以 O(1) 得到一个字串的哈希值。
inline unsigned long long check(int l,int r){ return h[r]-h[l-1]*pre[r-l+1]; }
其中,乘以 p[r-l+1] 相当于左移了 r-l+1 位。
同样,我们可以 O(1) 得到字串中删除一个字符后的hash值。
inline unsigned long long sum(int l,int r,int k){ return check(l,k-1)*pre[r-k]+check(k+1,r); }
枚举每一个位置,剩下的应是两个相同的字符串,根据hash值判断一下。
上完整代码
#include<cstdio> #include<iostream> #include"cstring" using namespace std; #define maxn 2000002 string a,b,c,d; int n,mid,l1,l2,h[maxn],pre[maxn]; char s[maxn]; int ans; inline unsigned long long check(int l,int r){ return h[r]-h[l-1]*pre[r-l+1]; } inline unsigned long long sum(int l,int r,int k){ return check(l,k-1)*pre[r-k]+check(k+1,r); } inline void out(){ if(!ans)printf("NOT POSSIBLE"); else if(ans==1||c==d)cout<<(c.size()?c:d); else printf("NOT UNIQUE"); } inline void work(){ l1=check(mid+1,n); for(int i=mid+1;i<=n;i++)a.push_back(s[i]); for(int i=1;i<=mid;i++){ l2=sum(1,mid,i); if(l1==l2){ ans++; c=a; break; } } l2=check(1,mid-1); for(int i=1;i<mid;i++)b.push_back(s[i]); for(int i=mid;i<=n;i++){ l1=sum(mid,n,i); if(l1==l2){ ans++; d=b; break; } } out(); } int main(){ scanf("%d%s",&n,s+1); mid=(n+1)>>1; if(!(n&1))return printf("NOT POSSIBLE"),0; pre[0]=1; for(int i=1;i<=n;i++){ pre[i]=pre[i-1]*733; h[i]=h[i-1]*733+(s[i]-'A'+1); } work(); return 0; }