Problema de subsecuencia simple
Se le proporciona un conjunto \ (S \) de cadenas que consta de 0
y 1
, y un número entero \ (K \) .
Encuentre la cadena más larga que sea una subsecuencia de \ (K \) o más cadenas diferentes en \ (S \) . Si hay varias cadenas que satisfacen esta condición, encuentre la cadena lexicográfica más pequeña.
Aquí, \ (S \) se da en el siguiente formato:
-
Los datos que se le proporcionan directamente son un entero \ (N \) y \ (N + 1 \) cadenas \ (X_0, X_1, ..., X_N \) . Para cada \ (i ~ (0 \ leq \ i \ leq \ N) \) , la longitud de \ (X_i \) es \ (2 ^ i \) .
-
Para cada par de dos enteros \ ((i, j) ~ (0 \ leq \ i \ leq \ N, 0 \ leq \ j \ leq \ 2 ^ i-1) \) , el \ (j \) -th El carácter de \ (X_i \) es
1
si y solo si la representación binaria de \ (j \) con \ (i \) dígitos (posiblemente con ceros a la izquierda) pertenece a \ (S \) . Aquí, el primer y el último carácter en \ (X_i \) se denominan \ (0 \) -th y \ ((2 ^ i-1) \) -th caracteres, respectivamente. -
\ (S \) no contiene una cadena con una longitud \ (N + 1 \) o más.
\ (N \ leq 20 \) .
Solución
Hamster "Conferencias seleccionadas sobre planificación dinámica".
Como no hay muchas cadenas posibles \ (S \) , entonces, para cada cadena \ (S \) , cuente cuántas subcadenas de la cadena establecida es.
Considere construir algo como un autómata.
Establezca un estado \ ((S, T) \) para indicar que ahora hay una cadena \ (S \) , seguida de una subsecuencia \ (T \) .
La transferencia es similar al proceso de caminar en el autómata de subsecuencia, agregando 0
y siguiendo 1
puede ir a dos estados por separado, y hay una transferencia sin agregar ningún carácter y luego finalizar. Este estado constituye un DAG.
Al mismo tiempo, este DAG tiene una muy buena propiedad, ya que está construido por un método similar a los autómatas de subsecuencia, por lo que el camino entre los dos puntos es único.
Según el análisis anterior, si \ (S \) es una subsecuencia de \ (T \) , entonces si y solo si \ ((\ varnothing, T) \) puede ir a \ ((S, \ varnothing) \) , Aquí \ (\ varnothing \) se usa para denotar una cadena vacía.
Como la ruta es única, solo cuente la ruta directamente en el DAG
Como este estado satisface \ (| S | + | T | ≤ N \) , el número de estados es \ (O (N × 2 ^ N) \) . Transferencia \ (O (1) \) , la complejidad del tiempo también es \ (O (N × 2 ^ N) \) .
El punto ingenioso de este problema es que, considerando la cadena S en cada conjunto, permite que contribuya a todas sus subsecuencias sin peso ni fugas. La violencia solo se puede hacer en un autómata de subsecuencia para cada cadena, pero si observa que el autómata de subsecuencia se puede suprimir y algunas propiedades relacionadas más adelante, el problema está resuelto.
Código de referencia: https://www.cnblogs.com/nealchen/p/AGC024F.html
Con el fin de describir la longitud de la cadena (para
0
aquellos con guiones ), agregamos una cadena delante de la cadena1
para describir la longitud de la cadena.
#define clz __builtin_clz
char str[(1<<20)+1];
int*F[1<<21],trans[1<<21][2];
int main(){
int n=read<int>(),K=read<int>();
F[1]=new int[1<<(n+1)];
F[1][0]=0;
for(int i=0;i<=n;++i){
int p=1<<i;
scanf("%s",str);
for(int j=0;j<p;++j) F[1][p+j]=str[j]-'0'; // use a leading 1 to describe the length
for(int j=0;j<p;++j) trans[p+j][1]=j;
trans[2*p-1][0]=0; // doesn't exist
for(int j=1;j<p;++j) trans[2*p-1-j][0]=j^((1<<(31-clz(j)))-1);
}
int ans=1;
for(int i=1;i<=n;++i){
int p=1<<i;
for(int j=2*p-1;j>=p;--j){
F[j]=new int[1<<(n-i+1)];
memset(F[j],0,sizeof(int)<<(n-i+1));
for(int k=1;k<1<<(n-i+2);++k) F[j][trans[k][j&1]]+=F[j>>1][k];
F[j][0]=0;
if(accumulate(F[j],F[j]+(1<<(n-i+1)),0)>=K) ans=j;
}
}
for(int i=31-clz(ans)-1;i>=0;--i) printf("%d",ans>>i&1);
puts("");
return 0;
}