bzoj 4962 problema de cadena simple

El efecto de visualización del blog es mejor

Breve descripción del título.

Proporcione una matriz de longitud \ (n \) \ (a \) y pregunte cuántos intervalos tiene, satisfaga:

  1. Longitud uniforme
  2. Primera mitad y segunda mitad isomorfismo cíclico

\ (n \ le 5000, a_i \ le 5000 \)

Ideas

Las dos cadenas \ (a, b \) son isomorfismo cíclico, entonces \ (a \) debe dividirse en dos cadenas \ (u, v \) y luego \ (b \) se expresa como \ (v, u \) .

就 比如\ (a = \ texttt {"abcde"}, b = \ texttt {"cdeab"} \)\那么\ (a = \ texttt {"ab" + "cde"}, b = \ texttt {"cde "+" ab "} \)

Entonces estas dos cadenas ahora son adyacentes, es decir, hay una forma continua \ (uv | vu \) . Considere enumerar la línea divisoria en el medio y luego calcular cuántos cumplen las condiciones en ambos lados. Esto puede ser capaz de usar agua de hachís, pero tenemos que pensar en una forma seria (* *)

En general, ¿qué hacemos con tales problemas de "bloque de palíndromo" ⊙ (・ ◇ ・)?

Piense en el problema de las fuerzas de código 932G . Podemos invertir la primera mitad del \ (uv \) e insertarlo uno por uno en el \ (vu \) de la segunda mitad . De esta manera, dos cadenas de palíndromo de longitud uniforme se unirán después de la inserción (/ ≧ ▽ ≦ /)

Por qué se vuelve así

Primero considere el caso de una cadena. Ahora hay un \ (u \) , suponiendo que consta de tres caracteres \ (a, b, c \) . Lo invertimos, y luego lo insertamos uno por uno, se convierte en:

\ (\ color {rojo} c \ color {negro} a \ color {rojo} b \ color {negro} b \ color {rojo} a \ color {negro} c \)

Los recién insertados se muestran en rojo, y los originales se muestran en negro. ¡Entonces descubrimos que se convirtió en un palíndromo!

Es fácil generalizar y demostrar que no importa cuánto tiempo sea, esto siempre se convertirá en una cuerda de palíndromo.

Luego considere el caso en que dos cadenas \ (u, v \) se unen. Si invertimos \ (u + v \) y los insertamos uno por uno en \ (v + u \) , ¿qué será?

Sea \ (s '\) la cadena inversa de \ (s \) . Entonces obviamente \ ((u + v) '= v' + u '\) . Después de insertarlo en \ (v + u \) , la primera cadena \ (| v | \) se convertirá primero en una cadena de palíndromo de longitud \ (2 | v | \) , seguida de \ ( | u | \) las cadenas se convertirán en una cadena de palíndromo de longitud \ (2 | u | \) . Luego, el conjunto se convierte en una cadena de palíndromo de dos pares de longitud \ (2 | v | +2 | u | \) .

Por ejemplo, \ (u = \ texttt {"ab"}, v = \ texttt {"cd"} \) , después de insertarlo, se convierte en: La fórmula explota, haga clic en mí

(Es posible que no sepa lo difícil que es esta fórmula, solo para dar un ejemplo de la imagen ... Ay, o (╥﹏╥) o)

Entonces solo necesitamos usar Manacher para contar cuántas cuerdas de palíndromo (~  ̄ ▽  ̄ ~)

Deje que \ (pre [i] \) indique la longitud máxima que se puede omitir desde \ (i \) hacia adelante, de modo que la parte omitida sea una cadena de palíndromo. Entonces \ (f [i] \) es el centro del palíndromo.

Use \ (last \) para registrar la ubicación del último prefijo de palíndromo. La posición actual es \ (i \) . Si \ ([último, i] \) es una cadena de palíndromo, o \ ([i-pre [i] + 1, i] \) es una cadena de palíndromo, entonces la \ actual (i \) es legal ~ ☆, respuesta ++.

Entonces, ¿cómo juzgar si \ ([l, r] \) es una cadena de palíndromo ⊙ (・ ◇ ・)? Establezca \ (mid = (l + r) / 2 \) y vea si \ (f [mid] \ ge (r-l + 1) / 2 \) está satisfecho .

Código

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
    #define N 14444
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)
    #define Tra(i,u) for(int i=G.Start(u),v=G.To(i);~i;i=G.Next(i),v=G.To(i))
    #define p_b push_back
    #define sz(a) ((int)a.size())
    #define iter(a,p) (a.begin()+p)
    int I()
    {
        int x=0;char c=getchar();int f=1;
        while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return (x=(f==1)?x:-x);
    }
    void Rd(int cnt,...)
    {
        va_list args; va_start(args,cnt);
        F(i,1,cnt) {int* x=va_arg(args,int*);(*x)=I();}
        va_end(args);
    }
 
    int n; 
    int a[N];
    void Input()
    {
        n=I();
        F(i,1,n) a[i]=I();
    }
 
    int s[N];
    int f[N],pre[N];
    int calc(int p)
    {
        int l=p,r=p+1;
        int cnt=0;
        while(l>=1 and r<=n) s[++cnt]=a[l],s[++cnt]=a[r],--l,++r;
 
        F(i,0,cnt+1) f[i]=pre[i]=0;
        int id=1,Max=1;
        F(i,1,cnt) 
        {
            f[i]=min(max(Max-i,0),f[id+(id-i)]);
            while(i+f[i]+1<=n and i-f[i]>0 and s[i+f[i]+1]==s[i-f[i]]) ++f[i]; 
            if (i+f[i]>=Max) Max=i+f[i],id=i;
            pre[i+f[i]]=max(pre[i+f[i]],f[i]);
        }
        D(i,cnt,1) pre[i]=max(pre[i],pre[i+1]-1);
        Ds(i,cnt,1,i-=2) pre[i]*=2;
 
        int ans=0,last=0;
        Fs(i,2,cnt,i+=2) 
        {
            if (f[i/2]==i/2) last=i;
            if (f[(i+last)/2]>=(i-last)/2 or f[(i-pre[i])/2]>=(i-pre[i])/2) ++ans;
        }
        return ans;
    }
    void Soviet()
    {
        int ans=0;
        F(i,1,n-1) ans+=calc(i);
        printf("%d\n",ans);
    }
 
    #define Flan void
    Flan IsMyWife()
    {
        Input();
        Soviet();
    }
}
int main()
{
    Flandre_Scarlet::IsMyWife();
    getchar();getchar();
    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/LightningUZ/p/12733406.html
Recomendado
Clasificación