Educación Codeforces Ronda 94 (Clasificado para Div.2) AE 题 解

Educación Codeforces Ronda 94 (Clasificado para Div.2) Solución de problemas de AE
// escrito en el valor de calificación 2075/2184
// Una vez finalizado el tercer examen,
se reanudará el entrenamiento normal. // El próximo cf comenzará a tocar
la E y esta La pregunta que escribí hace un tiempo es exactamente la misma ...

Enlace del concurso: https://codeforces.com/contest/1400
Una pregunta
estructura simple

Dada una cadena a con una longitud de 2n-1 que solo contiene 0 y 1, ahora necesita construir una cadena b con una longitud de n que satisfaga cualquier subcadena continua de longitud n en a y que tenga al menos una posición Los números de arriba son los mismos.

Tenga en cuenta que la longitud de la cadena a es 2n-1, y hay una posición especial en el medio, el enésimo carácter. Este carácter aparece en cualquier subcadena continua de la cadena a de longitud n.
La posición de este carácter en estas subcadenas consecutivas solo satisface las n posiciones 1-n.
Construimos directamente una cadena de longitud n, todos los cuales son el enésimo carácter de una cadena.

#include<bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        string s;
        cin>>s;
        char c=s[n-1];
        for(int i=0;i<n;i++) cout<<c;
        cout<<endl;
    }
}

Pregunta B
Codicia, violencia

El título significa que hay dos personas, cada una con una capacidad de mochila. Ahora hay cnts espadas de tamaño sy cntw hachas de tamaño W. Ahora te preguntaré cuántas armas pueden llevar los dos.

Primero, realice un proceso codicioso, asumiendo que s <= w, es decir, el peso de la espada no es mayor que el del hacha, en este momento debemos tomar tantas espadas como sea posible.
La prueba es la siguiente:
si se cumple cierto esquema, no se toma la espada, pero se toma el hacha. Dado que el peso de la espada no es más pesado que el del hacha, cualquier hacha nuestra puede ser reemplazada por un número igual de espadas y hay más espacio para ella.
Esto prueba que la selección preferencial de espadas es correcta avariciosa.

Luego observe que el número de espadas y hachas está dentro de 2e5, podemos enumerar cuántas espadas ha tomado la primera persona por la fuerza y ​​realizar el proceso codicioso para cada enumeración.

#include<bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        ll p,f;
        ll cnts,cntw,s,w;
        cin>>p>>f>>cnts>>cntw>>s>>w;
        ll ans=0;
        if(s>w) swap(cnts,cntw),swap(s,w);
        for(ll i=0;i*s<=p&&i<=cnts;i++)
        {
    
    
            ll first_s,first_w,second_s,second_w;//first代表第一个人拿的道具,s代表剑,w代表斧头
            first_s=i;//第一个人拿走i把剑
            second_s=min(f/s,cnts-first_s);//第二个人尽可能多拿剑,但是拿的个数不能超过剩下的剑的数量
            first_w=min((p-first_s*s)/w,cntw);//第一个人剩余的背包容量,尽可能多得拿斧头
            second_w=min((f-second_s*s)/w,cntw-first_w);//第二个人接着拿剩下的斧头,注意背包容量是剩余的,斧头个数也是剩余的
            ans=max(ans,first_s+first_w+second_s+second_w);
        }
        cout<<ans<<endl;
    }
}


Estructura de la pregunta C , implementación

La pregunta significa que dada una cadena a de longitud n que solo contiene 0 y 1 y un valor de distancia x, necesita construir una cadena b de longitud n que solo contenga 0 y 1 para que la cadena a pueda ser de caracteres La cadena b se obtiene de acuerdo con las siguientes reglas:
Para el i-ésimo carácter en la cadena a, si el subíndice de i + x o ix está entre 1-n, y el i + x o ixth carácter en la cadena b El carácter es 1, entonces el i-ésimo carácter de la cadena a también debe ser 1; de lo contrario, es 0.

En primer lugar, dada la relación de valores entre x y n, podemos saber que para cualquier i, al menos uno de i + x y ix está en el rango de 1-n.
Para a [i]:
si a [i] = 0, entonces b [ix] y b [i + x] también deben ser 0.
Si a [i] = 1, entonces b [ix] y b [i + x] si al menos uno de ellos es 1

Lo siguiente es el proceso de construcción, tenemos que pensar en un método de construcción, la posición de construcción actual ya no afectará la posición que hemos construido antes.
Observe las reglas especiales de esta pregunta: para a [i], solo hay dos posiciones de las que debemos preocuparnos, b [ix] y b [i + x].
Para diferentes valores de i, como i1 <i2, i1 + x e i2 + x no son iguales, i1-x e i2-x tampoco son iguales, solo i1 + x e i2-x pueden ser iguales.

Podemos construir los correspondientes ix e i + x en b de acuerdo con el subíndice i en a de pequeño a grande.
En el proceso de construcción, para la posición actual i, b [i + x] no se ha construido en el proceso de construcción anterior, y b [ix] puede haberse construido.
Si a [i] = 1, entonces necesitamos comprobar si hay 1 en b [ix] yb [i + x], si no hay 1, y si hay una posición que construir para que construyamos 1, si no se satisface, no podemos Construye metas. Cuando hay una posición para construir, si b [ix] puede construirse, entonces construya b [ix] como 1, pero no puede construir y luego construya b [i + x], porque b [i + x] afectará a [i + 2x ] Tiene un impacto, deberíamos adoptar una estrategia codiciosa para construir el lado izquierdo primero.
Si a [i] = 0, entonces necesitamos verificar si b [ix] y b [i + x] son ​​ambos 0, y construir ambas posiciones a 0. Si no se satisfacen, entonces no podemos construir el objetivo.

Se puede implementar de acuerdo con esta idea de estructura.

#include<bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        string s1,s2;
        cin>>s1;
        int n=(int)s1.size();
        s2.resize(n,'!');//s2为我们构造的字符串,一开始全部置为字符'!'代表该位置为待构造
        int x;
        cin>>x;
        bool flag=1;//指示目标字符串能否被构造,1代表可以
        for(int i=0;i<n;i++)//s1字符串中按照下标从小到大依次扫过去
        {
    
    
            if(s1[i]=='0')//当s1[i]=0的时候,s2[i-x]和s2[i+x]必须都为0
            {
    
    //由于s2[i+x]不可能在前面的构造过程中被构造过,因此第一个判断可行性的if里面没考虑
                if(i-x>=0&&s2[i-x]=='1') flag=0;//如果s2[i-x]在之前的构造过程中被构造了1,那么与当前条件矛盾
                if(i-x>=0) s2[i-x]='0';//构造左右两个位置为0
                if(i+x<n) s2[i+x]='0';
            }
            else
            {
    
    
                bool f=0;
                if(i-x>=0&&s2[i-x]=='1') f=1;//检测左右位置是否已经存在1
                if(!f)//如果不存在则需进行构造1
                {
    
    
                    if(i-x>=0&&s2[i-x]=='!') s2[i-x]='1';//优先构造左侧
                    else if(i+x<n) s2[i+x]='1';//构造右侧
                    else flag=0;//两侧都无法构造,则产生矛盾,目标字符串无法构造
                }
            }
        }
        for(int i=max(n-x,0);i<n;i++) if(s2[i]=='!') s2[i]='0';
        //注意上述构造过程结束后,目标字符串中的末尾部分是可能存在未构造部分的,任意构造均可
        //具体原因不表,思考上述构造过程即可
        if(flag) cout<<s2<<endl;
        else cout<<-1<<endl;
    }
}

Pregunta D
violencia, prefijo y

Dada una secuencia a de longitud n (n <= 3000), necesitas calcular cuántos pares (i, j, k, l) satisfacen 1 <= i <j <k <l <= n, y a [ i] = a [k], a [j] = a [l].

Tenga en cuenta que la n en esta pregunta es muy pequeña, por lo que podemos adoptar algunos enfoques relativamente violentos.
Dado que hay dos pares de números iguales y cuatro subíndices, necesitamos encontrar al menos dos subíndices como la posición fija inicial (el consumo de complejidad de tiempo es n 2 , nivel 1e6).
Si arreglamos i y j, o k y l (es decir, arreglamos el lado izquierdo o el derecho de dos pares de números iguales), tomemos la fijación de i y j como ejemplo, entonces consideramos cómo k y l satisfacen , Lo encontraremos muy difícil en este momento, porque tenemos que considerar tanto a [i] = a [k], a [j] = a [l], y también considerar k <l, y en este momento tanto los límites de k como de l Es mayor que j, es difícil calcular el número de casos .
Entonces consideramos que un par de números iguales se toma como subíndice izquierdo y el otro par de números iguales se toma como subíndice derecho. Consideramos arreglar j y k, luego buscamos i y l. En este momento, la posición de i debe ser menor que j, y la posición de l debe ser mayor que k, ya que j <k, lo que significa que cuando se cumplen las condiciones anteriores, i debe ser menor que l.
Podemos usar sum [i] [j] para registrar los primeros i dígitos de la secuencia (porque n es muy pequeño, la complejidad espacio-temporal es 1e6 y no hay problema), el número j aparece varias veces, es decir, el prefijo y la matriz. Cuando arreglamos los subíndices j y k, usamos el prefijo y la matriz para consultar cuántos números con subíndices menores que j son iguales a a [k], denotados como x, y luego consultamos números con subíndices mayores que k que son iguales a [ Hay varios de j], denotados como y. Para las partes izquierda y derecha, cualquier emparejamiento es una respuesta, por lo que la respuesta acumulada es x × \ veces× y。

Como resultado, preprocesamos el prefijo y la suma de la matriz (complejidad 1e6), luego enumeramos violentamente los subíndices de j y k (complejidad 1e6) y usamos el prefijo y la matriz para calcular cada caso (O (1)), i ¿Cuántos esquemas y l se pueden agregar a ans.

#include<bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=3e3+7;

int n;
int num[maxn];
int sum[maxn][maxn];//前缀和数组,sum[i][j]记录num数列中的前i个数字中,j出现了几次

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        for(int i=0;i<n;i++)
            for(int j=1;j<=n;j++) sum[i][j]=0;//不要用memset,避免tle,清理上次循环用过的部分即可
        ll ans=0;
        cin>>n;
        for(int i=0;i<n;i++)
        {
    
    
            cin>>num[i];
            if(i)
                for(int j=1;j<=n;j++)//先继承前i-1个数字中,各个数字的出现情况
                    sum[i][j]=sum[i-1][j];
            sum[i][num[i]]++;//当前位置的数字个数+1
        }
        for(int j=1;j<n;j++)
            for(int k=j+1;k<n;k++)
            {
    
    
                int i=sum[j-1][num[k]];//i的位置需要满足小于j,且对应数字等于num[k]
                int l=sum[n-1][num[j]]-sum[k][num[j]];//l的位置需要满足大于k,且对应数字等于num[j]
                ans+=i*l;
            }
        cout<<ans<<endl;
    }
}

Pregunta E
Codicioso, conclusión, divide y vencerás, dfs

// Acabo de escribir exactamente la misma pregunta en el campo de entrenamiento hace algún tiempo ... Sí, debería estar en cf.

La pregunta significa que dada una secuencia numérica de longitud n que contiene solo números naturales (n <= 5000), tiene dos formas de operación: la
primera es seleccionar un cierto número y cambiar este número a 0.
El segundo es seleccionar un área continua, donde cada número debe ser distinto de cero, de modo que el valor de cada número sea -1.
Ahora pregunte cuántas operaciones necesita al menos para establecer la secuencia completa en 0.

Para una secuencia de longitud n, si no tomamos la segunda operación y solo usamos la primera operación, el número de operaciones requeridas es n.

Luego considere usar la segunda operación mientras también usa la primera operación.
Defina Min como el número más pequeño en la secuencia actual, que también es el número máximo de veces que podemos usar la primera operación en la secuencia completa de 1-n.
En primer lugar, el proceso codicioso, cada vez que realizamos la segunda operación, debemos elegir la parte más larga tanto como sea posible, de lo contrario habrá la misma o mejor solución.

Después de eso, necesitamos usar la segunda operación varias veces en toda la secuencia de 1-n. En el proceso de pensamiento aquí, para que podamos realizar la segunda operación x veces, x <Min, lo que significa que todavía hay espacio para que continúe la segunda operación. En este momento, solo realizaremos la primera operación. Dado que cada número en la secuencia es mayor o igual que Min, cada número no es 0 en este momento. Necesitamos realizar la primera operación n veces.
El número total de operaciones en este momento es x + n, que es más que el número total de operaciones x donde realizamos directamente la primera operación en cada posición.
De esto tenemos otra conclusión codiciosa. Para una secuencia de longitud n, el valor mínimo es Min. Después de realizar la primera operación n veces, o realizar la segunda operación Min veces, continúe realizando las operaciones anteriores en un bucle . Después de realizar la segunda operación Min veces, la secuencia original se dividirá en un número de subsecuencias continuas distintas de cero, y el proceso anterior se puede realizar de forma recursiva para cada subsecuencia continua distinta de cero.

#include<bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define llINF 9223372036854775807
using namespace std;

ll n;
vector<ll>num;

ll dfs(vector<ll>now)
{
    
    
    ll temp=0,len=now.size();//temp为对整个数列now使用Min次第一种操作后,对剩余部分清零还需要的操作次数
    ll Min=llINF;
    for(ll i=0;i<len;i++)
        Min=min(Min,now[i]);
    vector<ll>next;
    for(ll i=0;i<len;i++)
    {
    
    
        if(now[i]==Min)
        {
    
    
            if(next.size())
            {
    
    
                temp+=dfs(next);//递归计算进行Min次操作后,剩下的连续非0部分还需多少次最少操作
                next.clear();
            }
        }
        else next.push_back(now[i]-Min);
    }
    if(next.size()) temp+=dfs(next);
    return min(len,Min+temp);//len为只进行第二种操作的操作次数,即为数列now长度
}

int32_t main()
{
    
    
    IOS;
    cin>>n;
    num.resize(n);
    for(auto &x:num) cin>>x;
    cout<<min(n,dfs(num))<<endl;//原数列不一定是连续的非0序列,但是这种写法的dfs是可以处理这种情况的
}

Supongo que te gusta

Origin blog.csdn.net/StandNotAlone/article/details/108294510
Recomendado
Clasificación