Codeforces Round # 665 (Div.2) Solución de problemas de AD

** Codeforces Round # 665 (Div.2) Solución del problema AD **
// Escrito en el valor de calificación 2075/2184
// La pregunta recién hecha en la tarde, debe practicar tres antes del 28, y la competencia durante este tiempo debe ser de palomas Arriba

Enlace del concurso: https://codeforces.com/contest/1401 Pregunta
A
Pensamiento simple

La pregunta significa que hay un punto A ubicado en (n, 0) en el eje x. Ahora, dado un valor k, necesita encontrar un punto B ubicado en (m, 0) que satisfaga m <= n, haciendo que el origen (0,0) El valor absoluto de la diferencia entre la distancia a B y la distancia de A a B es igual a k. (N, m, k son todos números enteros)
Si no se puede encontrar tal punto, podemos realizar cualquier número de operaciones en el punto A, y podemos aumentar o disminuir el valor de n en 1.
Ahora necesita generar el número mínimo de operaciones para que podamos encontrar el punto B que cumple con los requisitos.

Primero, cuando n = k, podemos elegir el punto B como (0, 0). En este caso, la longitud de OB es 0, la longitud de AB es n = k, la diferencia entre las dos distancias es k para cumplir con los requisitos y se requiere el número de operaciones. Es 0.

Si n <k, dado que la suma de las longitudes de OB y ​​AB es igual an, significa que la diferencia entre las dos longitudes es la mayor y no puede ser igual a k. No necesitamos aumentar la operación de n y acercarnos a la situación en la que n = k. El número requerido de operaciones es kn veces.

Si n> k, no significa que no sea necesaria ninguna operación en este momento. También es necesario considerar la paridad de n y k. Suponiendo que la longitud de OB es L1, la longitud de AB es L2 y L1> L2, dado que n, myk deben ser todos números enteros, las longitudes de L1 y L2 también son números enteros.
Dado que L1 + L2 = n, L1-L2 = k, obtenemos L1 = L2 + k
para obtener 2 × \ times× L2 = nk, lo que significa que nk debe ser un número par.
Por lo tanto, cuando nk no es un número entero, también necesitamos realizar una operación +1 en 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 n,k;
        cin>>n>>k;
        if(k<n) cout<<(n-k)%2<<endl;
        else cout<<k-n<<endl;
    }
}

Pregunta B
Clasificación, codicioso, pensamiento simple

Ahora hay dos series que contienen solo 0, 1, 2 y la longitud de las dos series es igual.
La primera secuencia tiene a1 con 0, b1 con 1 y c1 con 2.
La segunda secuencia tiene a2 0s, b2 1s y c2 2s.

Ahora debe hacer coincidir las dos columnas de estos dos números,
el primer número del número de fila seleccionado se proporciona x, la segunda columna el número de números seleccionados de y
cuando x = y, la respuesta a la acumulación 0
cuando Cuando x> y, suma x × \ veces× y a la respuesta
Cuando x <y, acumula -x× \ veces× y a la respuesta

Ahora necesita generar la máxima respuesta final posible.

En esta pregunta, solo hay tres números de 0, 1 y 2 en cada secuencia, y hay 0. El cálculo final es la multiplicación. Discutimos directamente las siguientes 9 situaciones y es fácil encontrar que
solo cuando x = 2, y = 1, habrá un aumento positivo en la respuesta final, y
solo cuando x = 1, y = 2, habrá un aumento negativo en la respuesta final. En
otros casos, el aumento de la respuesta es 0.

Las dos opciones de aumento positivo y aumento negativo no están en conflicto, podemos elegir directamente el aumento positivo con más logaritmos y el aumento negativo con el menor logaritmo.

Lo más logarítmico x = 2, y = 1 que podemos aumentar es el mínimo del número de 2 en la primera serie y el número de 1 en la segunda serie.
Después de eso, esperamos que los logaritmos de x = 1 e y = 2 sean lo menos posible, por lo que dejamos que el 2 en la segunda serie se empareje con 0 y 2 en la segunda serie tanto como sea posible, y el resto solo se puede emparejar con 1 emparejamiento, en este caso el número mínimo de pares.

#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 a1,b1,c1,a2,b2,c2;
        cin>>a1>>b1>>c1>>a2>>b2>>c2;
        ll ans=0;
        ll temp=min(c1,b2);//考虑我们增加的2*1的对数最多有多少
        ans+=temp*2;c1-=temp;//累加到答案上,并且减去使用掉的第一个数列中的2的个数
        temp=max(0ll,c2-c1-a1);//考虑减少的1*2的对数最少有多少
        //我们尽可能让第二个数列的2与第一个数列的2或者0配对,剩下的无可奈何只能与1配对
        //这里要和0取个max,因为c2-c1-a1可能为负数。
        ans-=2*temp;
        cout<<ans<<endl;
    }
}

Tipo de pregunta C
, pensamiento general

Dada una secuencia de longitud n, donde el número más pequeño es Min, puede seleccionar dos números xey con diferentes subíndices en esta secuencia para satisfacer mcd (x, y) = Min, intercambiar estos dos números posición.
Ahora pregúntele si puede hacer la secuencia de números ordenados de pequeños a grandes después de cualquier número de las operaciones anteriores.

En primer lugar, debemos darnos cuenta de que en la serie original, el valor no puede dividir Min , lo que significa que el factor no contiene Min en absoluto, por lo que el mcd de este y otros números no deben ser Min, por lo que su posición no se puede cambiar .

Luego, en la secuencia original, excluyendo los números que no pueden ser enteros Min, y los números restantes que pueden dividir Min, ¿hasta qué punto podemos clasificarlos a través de la operación dada en la pregunta?
Debe haber un número en la secuencia igual a Min Sí, Min y cualquier mcd que pueda dividirlo debe ser igual a Min, lo que significa que Min se puede intercambiar con cualquier otro número restante .
Una vez que un número satisface la posición de intercambio mencionada anteriormente con cualquier otro número de posición, podemos usar este número para realizar un proceso de clasificación de inserción similar para clasificar la serie completa.

Es decir, los números que no pueden dividir Min por el valor, no podemos cambiar su posición, pero los números que pueden dividir Min, podemos ordenarlos de menor a mayor.

Por lo tanto, ordenamos directamente la secuencia numérica original. Tenga en cuenta que cuando los valores son iguales, debemos ordenar de subíndice pequeño a grande, porque los números que no pueden dividir Min pueden tener el mismo valor y sus posiciones no se pueden cambiar, es decir, el orden en la secuencia original Debe conservarse. Por lo tanto, no podemos utilizar directamente la ordenación rápida inestable. Compruebe si los números que no se pueden dividir en Mín son los mismos que el índice de posición original después de la clasificación . Si son diferentes, significa que no se pueden construir.

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

struct Node
{
    
    
    ll data,tar;
};

ll n,Min;//Min为数列中的最小值
vector<Node>node;

bool cmp(Node a,Node b)//数值为第一排序关键字,数值相等时按照原下标从小到大排序
//即一个稳定的快速排序
{
    
    
    if(a.data!=b.data) return a.data<b.data;
    else return a.tar<b.tar;
}

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        node.resize(n);
        Min=llINF;
        for(ll i=0;i<n;i++)
        {
    
    
            cin>>node[i].data;
            node[i].tar=i;
            Min=min(node[i].data,Min);
        }
        sort(node.begin(),node.end(),cmp);
        bool flag=1;
        for(ll i=0;i<n;i++)
        {
    
    
            if(node[i].data%Min&&i!=node[i].tar) flag=0;
            //如果当前的数值无法整除Min那代表它是无法被交换位置的
            //如果在稳定排序后的位置与其原位置不同,那么代表我们是无法得到稳定排序后的数列的
        }
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        node.clear();
    }
}

Pregunta D
Conclusión gráfica simple y codiciosa

Un árbol dado tiene n nodos y n-1 aristas. Ahora debe dar un valor a cada borde, y el valor correspondiente a los n-1 bordes debe multiplicarse por el número k dado. Dado que k puede ser muy grande, los datos de entrada de la pregunta son el resultado de k descomposición de factores primos.

Ahora es necesario acumular la suma de los valores de los bordes de la ruta simple entre dos puntos cualesquiera. El resultado final debe ser lo más grande posible y el número 1 debe ser lo más pequeño posible al construir un valor para cada borde.

Lo primero en lo que debemos pensar es en cuántas veces se ha acumulado en el resultado final para cada borde de este árbol.
Tome la imagen de la primera muestra del título como ejemplo:
Inserte la descripción de la imagen aquí
En la imagen de arriba, el borde en el medio tiene dos puntos 1 y 2 a la izquierda y dos puntos 3 y 4 a la derecha. Se calcula un total de 2 × \ veces para este borde× 2 = 4 veces. Es decir, el número de nodos de la izquierda se multiplica por el número de nodos de la derecha, porque la ruta simple desde el punto de la izquierda hasta el punto de la derecha debe pasar por el borde actual. El camino simple desde el punto de la izquierda al punto de la izquierda o el punto de la derecha al punto de la derecha no necesita pasar por el lado actual.

Podemos calcular el número de nodos secundarios de cada nodo a través del dfs comenzando desde el nodo raíz, y luego calcular cuántas veces se calcula cada borde en el resultado final.

Luego está el proceso de cómo construir el valor de estos n-1 bordes.
El título requiere que el producto numérico de estos n-1 aristas sea igual a k, por lo que el resultado de su descomposición de factores primos debe ser el mismo que k.
Cuando el número de factores primos obtenido al descomponer k factores primos es m <= n-1, adoptamos directamente el proceso codicioso y emparejamos el número de factores primos con el número de apariciones del borde en el resultado final. La falta de m <n-1 se llena con 1, y cualquier valor de 1 multiplicado por cualquier valor es igual al valor original.
Cuando m> n-1. Usando la misma estrategia codiciosa, multiplicamos los factores primos m- (n-1) +1 más grandes y los colocamos en el lado con el mayor número de ocurrencias. (La corrección de esta codicia se puede probar por contradicción). Luego, realice el mismo proceso de búsqueda codicioso que en el caso anterior.

#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 mod=1e9+7;

ll n,m,start;
vector<vector<ll>>to(1e5+7);//存边
vector<ll>sun;//sun[i]记录结点i包括自己有几个子节点,用于计算边被计算几次
deque<ll>k;//k分解质因子后得到的数列
deque<ll>edgenum;//存储每条边各自会被计算多少次累加到结果上,排序后用于贪心过程

void dfs(ll now,ll pre)//now为当前所在节点,pre为上一个节点
{
    
    
    for(ll i=0;i<to[now].size();i++)
    {
    
    
        if(to[now][i]!=pre)//不往回走
        {
    
    
            dfs(to[now][i],now);
            sun[now]+=sun[to[now][i]];//累加子树的子节点数当前节点上
        }
    }
    sun[now]++;//自身也算做一个子节点
    if(now!=start) edgenum.push_back((n-sun[now])*sun[now]);
    //对于now到pre的这条边来说,sun[now]为这条边“下面”的子节点数,那么n-sun[now]即为这条边"上面"的子节点数
}

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        for(ll i=1;i<=n;i++)
            to[i].clear();
        for(ll i=1;i<n;i++)
        {
    
    
            ll u,v;
            cin>>u>>v;
            to[u].push_back(v);
            to[v].push_back(u);
        }
        cin>>m;
        k.resize(m);
        for(ll i=0;i<m;i++) cin>>k[i];
        sort(k.begin(),k.end());//排序用于贪心
        for(ll i=1;i<=n;i++)//找一个出度为0的点,作为树的根进行dfs
            if(to[i].size()==1) start=i;
        sun.clear();sun.resize(n+1,0);
        edgenum.clear();
        dfs(start,-1);//dfs计算每条边会被计算几次到答案上,也就是每条边的权值
        sort(edgenum.begin(),edgenum.end());//排序用于贪心
        while(m>edgenum.size())//m为k数组的大小,如果m的个数大于边的个数,我们要贪心使得权值最大的边对应最大的乘积
        //不断累乘最大的值给第二大的数,缩小数组大小即可
        {
    
    
            k[m-2]=(k[m-2]*k[m-1]%mod);
            k.pop_back();
            m--;
        }
        while(m<edgenum.size())//再考虑m个数小于边的个数时,我们需要在剩下的边补1
        {
    
    
            k.push_front(1);
            m++;
        }
        ll ans=0;
        for(ll i=0;i<m;i++)//贪心过程,小的值配权值小的边,不断累加到答案上
        {
    
    
            ans=(ans+edgenum[i]%mod*k[i]%mod)%mod;
        }
        cout<<ans<<endl;
    }
}

Supongo que te gusta

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