contraparte digital [P4068] Luo Gu

título

enlaces a los temas: https://www.luogu.com.cn/problem/P4068
tienen \ (n \) tipo de figuras, la primera \ (i \) el número de especies es \ (a_i \) , hay \ (b_i \) a, los pesos son \ (C_i \) .
Si los dos números \ (a_i \) , \ (A_j \) satisface, \ (a_i \) es \ (A_j \) múltiplos, y \ (\ frac {a_i} { A_j} \) es un número primo,
entonces este dos números pueden ser emparejados, y obtener (C_i \ épocas C_J \) \ valor.
Un número sólo puede participar una vez vinculado, no puede participar en el emparejamiento.
Bajo la premisa de la suma del valor obtenido no es menor que cero, ¿cuántas veces se emparejaron a buscar.

pensamiento

Seguimos cada número después de la descomposición de los factores primos del factor de calidad (no pesado) de paridad número divide en dos categorías, obviamente, dos números de la misma clase no pueden ser emparejados porque deben tener un número par de factor de calidad comercial, para que el negocio no es ciertamente un número primo.
Por lo que estos dos juegos es un grafo bipartito. Consideramos que el siguiente ejemplo:

  • Set una \ (a [i] \) del factor de calidad tiene un número impar, desde la fuente hasta el punto (I \) \ incluso un flujo \ (C [I] \) , 0 el lado de los costes.
  • Configurar una \ (a [i] \) es un número par de factores primos, desde \ (I \) para conectar un flujo fregadero \ (C [I] \) , 0 el lado de los costos.
  • Si los dos conjuntos diferentes de puntos \ (i, j \) se puede combinar (proporcionado \ (I \) factor primo tiene un número impar), entonces el \ (I \) a \ (J \) está conectado a un flujo \ ( + \ infty \) , un coste de \ (c [i] \ veces c [j] \) lateral.

El siguiente mayor flujo de coste máximo se puede ejecutar. El caudal máximo es la respuesta.
Sin embargo, los costos y la corriente de flujo de costos en general es diferente, ya que el requisito de caudal costo general es el caudal máximo con la máxima / de poca monta, y este problema requiere "la suma del valor de no menos de 0", que es el costo de no menos de 0 flujo máximo.
Obviamente cada camino más largo más largo cuando el camino no es más que la última vez aumentada aumentada, si esta longitud del camino más largo no es negativo, entonces obviamente el mejor, de lo contrario será sin duda más grande y bajo la premisa de la costa de no menos de 0 así, debido a que la parte posterior de aumentar el camino más largo será más corta, por lo menos ingresos.

código

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=210,M=6e5,Inf=1e9;
int a[N],b[N],c[N],head[N],p[N],pre[N];
int n,S,T,tot=1;
ll maxflow,cost,dis[N];
bool vis[N];

struct edge
{
    int next,to,from,flow;
    ll cost;
}e[M];

void add(int from,int to,int flow,ll cost)
{
    e[++tot].to=to;
    e[tot].from=from;
    e[tot].flow=flow;
    e[tot].cost=cost;
    e[tot].next=head[from];
    head[from]=tot;
}

bool spfa()
{
    memset(dis,-0x3f3f3f3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(S); dis[S]=0;
    while (q.size())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for (int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].to;
            if (e[i].flow && dis[v]<dis[u]+e[i].cost)
            {
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if (!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    return dis[T]>-1e18;
}

bool addflow()
{
    ll minflow=1e18;
    for (int x=T;x!=S;x=e[pre[x]].from)
        minflow=min(minflow,1LL*e[pre[x]].flow);
    if (dis[T]<0) minflow=min(minflow,cost/(-dis[T]));
    for (int x=T;x!=S;x=e[pre[x]].from)
    {
        e[pre[x]].flow-=minflow;
        e[pre[x]^1].flow+=minflow;
    }
    maxflow+=minflow;
    cost+=minflow*dis[T];
}

void mcmf()
{
    while (spfa())
    {
        if (cost+dis[T]<0) return;
        addflow();
    }
}

int main()
{
    S=N-1; T=N-2;
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) scanf("%d",&b[i]);
    for (int i=1;i<=n;i++) scanf("%d",&c[i]);
    for (int i=1;i<=n;i++)
    {
        int x=a[i];
        for (int j=2;j*j<=x;j++)
            for (;x%j==0;x/=j) p[i]++;
        if (x>1) p[i]++;
        if (p[i]&1) add(S,i,b[i],0),add(i,S,0,0);
            else add(i,T,b[i],0),add(T,i,0,0);
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if ((p[i]&1) && abs(p[i]-p[j])==1 && (!(a[i]%a[j]) || !(a[j]%a[i])))
                add(i,j,Inf,1LL*c[i]*c[j]),add(j,i,0,-1LL*c[i]*c[j]);
    mcmf();
    printf("%lld\n",maxflow);
    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/stoorz/p/12527030.html
Recomendado
Clasificación