ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解【CF245H Queries for Number of Palindromes】

2022-06-07 19:03:31  阅读:126  来源: 互联网

标签:Palindromes CF245H int 题解 rep mid inline return include


我写完了发现自己是个傻逼。

为啥题解都是区间 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有