首页 > 其他分享 >CF1827C Palindrome Partition 题解

CF1827C Palindrome Partition 题解

时间:2023-11-29 18:23:24浏览次数:42  
标签:ch int 题解 mid long Palindrome CF1827C 回文 define

题目链接

点击打开链接

题目解法

首先考虑一个朴素的 \(dp\)
令 \(f_i\) 表示以 \(i\) 结尾的合法子串的个数
为了不重不漏,我们令 \(le_i\) 表示以 \(i\) 为右端点,离 \(i\) 最近的偶回文串的左端点,然后不难得到转移为 \(f_i=f_{le_i-1}+1\)
为什么不会漏?考虑以 \(i\) 为右端点,且比最短回文串长的子串一定可以拆分成若干个回文串

求 \(le_i\) 可以二分哈希求出最长的回文串 \([i-l,i+l)\),然后线段树覆盖即可维护
时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
const int N=500100;
int n,seg[N<<2],f[N];
char str[N];
struct Hash{
    int P;
    ull p[N],h[2][N];
    void build(){
        p[0]=1;
        F(i,1,n) p[i]=p[i-1]*P; 
        F(i,1,n) h[0][i]=h[0][i-1]*P+str[i];
        h[1][n+1]=0;
        DF(i,n,1) h[1][i]=h[1][i+1]*P+str[i];
    }
    ull gethash(int seq,int l,int r){
        if(!seq) return h[seq][r]-h[seq][l-1]*p[r-l+1];
        else return h[seq][l]-h[seq][r+1]*p[r-l+1];
    }
}ha[2];
void pushdown(int x){ if(seg[x]!=-1) seg[x<<1]=seg[x<<1^1]=seg[x],seg[x]=-1;}
void modify(int l,int r,int x,int L,int R,int v){
    if(L<=l&&r<=R){ seg[x]=v;return;}
    pushdown(x);
    int mid=(l+r)>>1;
    if(mid>=L) modify(l,mid,x<<1,L,R,v);
    if(mid<R) modify(mid+1,r,x<<1^1,L,R,v);
}
int le[N];
void get_seg(int l,int r,int x){
    if(l==r){ le[l]=seg[x];return;}
    pushdown(x);
    int mid=(l+r)>>1;
    get_seg(l,mid,x<<1),get_seg(mid+1,r,x<<1^1);
}
const int inf=1e9;
void work(){
    n=read();scanf("%s",str+1);
    ha[0].build(),ha[1].build();
    F(i,1,n<<2) seg[i]=-1;
    F(i,2,n){
        int l=0,r=n+1;
        while(l<r-1){
            int mid=(l+r)>>1;
            if(!(i-mid>=1&&i+mid-1<=n)){ r=mid;continue;}
            if(ha[0].gethash(0,i,i+mid-1)==ha[0].gethash(1,i-mid,i-1)&&
               ha[1].gethash(0,i,i+mid-1)==ha[1].gethash(1,i-mid,i-1)) l=mid;
            else r=mid;
        }
        // cout<<"!!!"<<i<<' '<<l<<'\n';
        if(l) modify(1,n,1,i,i+l-1,i);
    }
    get_seg(1,n,1);
    // F(i,1,n) cout<<le[i]<<' ';cout<<'\n';
    F(i,1,n) f[i]=0;
    F(i,1,n) if(le[i]!=-1) f[i]=f[le[i]*2-i-2]+1;
    LL ans=0;
    F(i,1,n) ans+=f[i];
    printf("%lld\n",ans);
}
int main(){
    ha[0].P=131,ha[1].P=131;
    int T=read();
    while(T--) work();    
    fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
    return 0;
}

标签:ch,int,题解,mid,long,Palindrome,CF1827C,回文,define
From: https://www.cnblogs.com/Farmer-djx/p/17865547.html

相关文章

  • NOIP2000提高组真题解析
    NOIP2000提高组真题解析第一题进制转换题目链接解析首先,我们知道对于10进制数x转2进制数,使用的算法是:求出x%2令x=x/2不断执行1,2,直至x为0,然后倒序输出步骤1的结果。一般可以用数组存步骤1的结果倒序输出或者使用dfs回溯回来再输出。对于负数的情况,比如\(-7=1*(-2)^3......
  • ISCTF 逆向题解
    ISCTF逆向题解用一个晚上的时间看了看ISCTF,有的题还蛮难的(毕竟得嘎嘎猜出题人想法)CrackMewinhex打开exe,修改标识头PFX为UPX然后放进UPXshell里面试试脱了,放进ida,直接反编译得到flagEasyReexeinfo看看这个是什么64位,放进ida反编译得到一段很清晰的逻辑反转+异或+单表代换。。。......
  • ICPC2022Xian L Tree 题解
    LinkICPC2022XianLTreeQuestion给出一个根为\(1\)的树,需要将树分成几个块每个块,一个块中的节点需要满足以下条件中的一个:对于所有的\(u,v\inS,\u\neqv\),满足\(u\insubtree(v)\)或\(v\insubtree(u)\)对于所有的\(u,v\inS,\u\neqv\),满足\(u\not......
  • [ABC277G] Random Walk to Millionaire 题解
    题目链接点击打开链接题目解法首先\(O(n^3)\)的\(dp\)是显然的,令\(f_{i,j,k}\)为第\(i\)步在\(j\),当前等级为\(k\)的\([i,n]\)步获得钱数的期望,转移枚举出边即可一个很妙的优化是:贡献都是\(k^2\)的形式,所以我们考虑维护\(k\)的\(0,1,2\)次幂,即\(\sum,\sum......
  • CF1900D - Small GCD 题解
    1900D-SmallGCD给定序列\(A\),定义\(f(a,b,c)\)为\(a,b,c\)中最小的次小的数的\(\gcd\),求:\[\sum_{i=1}^n\sum_{j=i+1}^n\sum_{k=j+1}^nf(a_i,a_j,a_k)\]题解目前来说有两种方法,都十分有启发意义,但是有共同的开头。考虑到\(A\)的顺序实际上没有......
  • SP19543 GSS8 - Can you answer these queries VIII 题解
    更好的阅读体验SP19543GSS8-CanyouanswerthesequeriesVIIIfhq+二项式定理。提供一个不太一样的思路。默认下标从\(1\)开始。首先插入删除,区间查询,想到可以平衡树维护或者离线下来做线段树。本文中是用的是fhq,好写一些。\(k\)非常的小,考虑对于每一个\(k\)的答......
  • 服务器数据库A的备份恢复到服务器B后出现问题解决
    消息10314,级别16,状态11,第2行尝试加载程序集ID65536时,Microsoft.NETFramework出错。服务器可能资源不足,或者程序集可能不受信任,PERMISSION_SET=EXTERNAL_ACCESS或UNSAFE。如上错误提示,解决办法: alterdatabasedatabasenamesettrustworthyon还有更改数据库......
  • 【题解】CF1550E Stringforces
    标签:DP\(B^+\)阅读须知:本题解较为详细地讲述的该题解法的思路和来龙去脉,但篇幅较长,请耐心阅读。Step1从题面获取信息我们考虑,因为最大值最小,所以我们首先想到二分答案。然后我们又看到\(k\leq17\)这个限制,所以会想到可能是关于一个\(2^k\)之类的复杂度。以上就是我......
  • ABC330 E Mex and Update 题解
    LinkABC330EMexandUpdateQuestion给一个数组\(a\),有\(Q\)次修改每次把\(a_i\)改成\(x\)问每次修改后,不在\(a\)数组中的最小非负数时多少Solution记录每个\(a_i\)出现的次数\(num\)每个修改操作可以看成时先删除,后添加用set维护为\(num_x=0\)的\(x\)......
  • UVA11275 3D Triangles 题解
    LinkUVA112753DTrianglesQuestion给你三维空间中的两个三角形,请判断它们是否有公共点。Solution如果在三维空间中相交,那么,肯定有一个三角形的某一条边穿过了另外一个三角形Code#include<bits/stdc++.h>usingnamespacestd;constdoubleeps=1e-9;structPoint3{......