题解【CF245H Queries for Number of Palindromes】
作者:互联网
我写完了发现自己是个傻逼。
为啥题解都是区间 DP 啊,提供一个不同的难写做法。
考虑求出 $f_{i,j}$ 表示 $[i,j]$ 的回文串的数量,这样对于询问能做到 $\Theta(1)$。
对于每一个 $f_{i,j-1}$ 可以转移到 $f_{i,j}$,加上“以 $s_j$ 结尾的左端点在 $[i,j]$ 中的回文串的数量”即可。
这个转移的时候直接算不太高明,考虑先求 $g_i$ 表示以 $s_i$ 为结尾的所有回文子串开头出现的位置集合。
这样我们在转移的时候在 $g_j$ 上二分一个位置即可。$g$ 可以用 vector 来实现。
$g$ 的求法就很简单了。我们直接枚举一个 $j(j\le i)$ 然后判断 $[j,i]$ 是否是回文子串即可。
这个操作用哈希可以实现,对于原串建立反串,两边判断一下就好了。
最后复杂度 $\Theta(n^2\log n+q)$。瓶颈在于二分。
竟然比大多数 $\Theta(n^2)$ 的做法跑的快。
#include<cstdio> #include<algorithm> #include<cstring> #include<ctime> #include<cstdlib> #include<climits> #include<queue> #include<vector> #define rep(i,a,b) for(register int i=a;i<=b;++i) #define Inf(a) memset(a,0x3f,sizeof(a)) #define Clear(a) memset(a,0,sizeof(a)) #define gra(i,u) for(register int i=head[u];i;i=edge[i].nxt) #define rev(i,a,b) for(register int i=a;i>=b;--i) using namespace std; typedef long long ll; inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0' or ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0' and ch<='9')s=s*10+(ch-'0'),ch=getchar(); return s*w; } const int INF=1e9+10; template<typename T> inline T Max(T x,T y){return x>y?x:y;} template<typename T> inline T Min(T x,T y){return x<y?x:y;} template<typename T> inline void Swap(T&x,T&y){T t=x;x=y;y=t;return;} template<typename T> inline T Abs(T x){return x>0?x:-x;} const int MAXN(5010); int n,q; char s[MAXN]; int dp[MAXN][MAXN]; vector<int>g[MAXN]; struct HASH { typedef unsigned long long ull; ull h[MAXN],fac[MAXN]; const ull Base=114514; inline void build(char*c) { fac[0]=1; rep(i,1,n) h[i]=h[i-1]*Base+(c[i]-'a'+1),fac[i]=fac[i-1]*Base; return; } inline ull get_hash(int l,int r){return h[r]-h[l-1]*fac[r-l+1];} }; HASH h1,h2; inline bool check(int l,int r) { int mid=(l+r)>>1; if((l+r)%2==0) return h1.get_hash(l,mid)==h2.get_hash(n-r+1,n-mid+1); else return h1.get_hash(l,mid)==h2.get_hash(n-r+1,n-(mid+1)+1); } inline int Find(int i,int x) { if(g[i].empty()) return -1; int l=0,r=g[i].size()-1,res(-1); if(g[i][l]>=x) return l; else if(g[i][r]<x) return -1; while(l<=r) { int mid=(l+r)>>1; if(g[i][mid]>=x) res=mid,r=mid-1; else l=mid+1; } return res; } inline int calc(int i,int j) { int p=Find(j,i); if(p==-1) return 0; return g[j].size()-p; } int main() { scanf("%s",s+1); n=strlen(s+1); h1.build(s); reverse(s+1,s+1+n); h2.build(s); rep(i,1,n) { g[i].push_back(i); rep(j,i+1,n) if(check(i,j)) g[j].push_back(i); } rep(i,1,n) sort(g[i].begin(),g[i].end()); rep(i,1,n) dp[i][i]=1; rep(i,1,n) rep(j,i+1,n) dp[i][j]=dp[i][j-1]+calc(i,j); q=read(); while(q--) { int l=read(),r=read(); printf("%d\n",dp[l][r]); } return 0; }
标签:Palindromes,CF245H,int,题解,rep,mid,inline,return,include 来源: https://www.cnblogs.com/UperFicial/p/16352956.html