Codeforces 739E:Gosha is hunting – 题解

主要思路

一眼可以看出一个 \(\Theta(n^3)\) 的 DP。其实用双带权二分就可以用 \(\Theta(n \log^2 n)\) 的时间搞了,但是我没写这个写法。

考虑一下被选择时的贡献。\(p_a, p_b\) 是单元贡献,考虑同时被选的贡献 \(1 – (1 – p_a)(1 – p_b) = p_a + p_b – p_a p_b\)。所以我们可以考虑最大费用最大流,来算这个式子。

需要注意的是,我们需要保证每一次代价都是正的,因为我们其实并不需要最大流,而只是相对的最大费用。

代码

// CF739E.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200;
const double eps = 1e-8;

int n, a, b, head[MAX_N], current, start_pos, end_pos, flow[MAX_N], pre[MAX_N];
double dist[MAX_N], acc_pi[MAX_N];
bool vis[MAX_N];

struct edge
{
    int to, nxt, weight;
    double cost;
} edges[MAX_N];

void addpath(int src, int dst, int weight, double cost)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    edges[current].weight = weight, edges[current].cost = cost, head[src] = current++;
}

void addtube(int src, int dst, int weight, double cost)
{
    addpath(src, dst, weight, cost);
    addpath(dst, src, 0, -cost);
}

bool spfa()
{
    for (int i = 1; i <= end_pos; i++)
        dist[i] = -0x3f3f3f3f3f3f3f3f, vis[i] = false, pre[i] = -1;
    queue<int> q;
    q.push(start_pos), dist[start_pos] = 0, vis[start_pos] = true, flow[start_pos] = 0x3f3f3f3f;
    while (!q.empty())
    {
        int u = q.front();
        q.pop(), vis[u] = false;
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            if (dist[edges[i].to] < dist[u] + edges[i].cost - eps && edges[i].weight > 0)
            {
                dist[edges[i].to] = dist[u] + edges[i].cost;
                flow[edges[i].to] = min(edges[i].weight, flow[u]), pre[edges[i].to] = i;
                if (!vis[edges[i].to])
                    q.push(edges[i].to), vis[edges[i].to] = true;
            }
    }
    return pre[end_pos] != -1;
}

double mfmc()
{
    double ret = 0;
    while (spfa() && dist[end_pos] >= eps)
    {
        int u = end_pos, flw = flow[end_pos];
        ret += flw * dist[end_pos];
        while (u != start_pos)
        {
            edges[pre[u]].weight -= flw, edges[pre[u] ^ 1].weight += flw;
            u = edges[pre[u] ^ 1].to;
        }
    }
    return ret;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &a, &b);
    int A = n + 1, B = n + 2;
    start_pos = B + 1, end_pos = B + 2;
    addtube(start_pos, A, a, 0), addtube(start_pos, B, b, 0);
    for (int i = 1; i <= n; i++)
    {
        double pi;
        scanf("%lf", &pi), acc_pi[i] = pi, addtube(A, i, 1, pi);
    }
    for (int i = 1; i <= n; i++)
    {
        double pi;
        scanf("%lf", &pi), acc_pi[i] = -acc_pi[i] * pi, addtube(B, i, 1, pi);
    }
    for (int i = 1; i <= n; i++)
        addtube(i, end_pos, 1, 0), addtube(i, end_pos, 1, acc_pi[i]);
    printf("%.10lf\n", mfmc());
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *