CodeForces Gym 101208 | 2013 World-Finals (需补坑)

感觉自己被虐千百遍,看着final的队伍做题速度++++很难受。
最后只做了6题。

A: Self-Assembly

题目大意

C: Surely You Congest

题目大意

给出一个无向有权图,已知每个点会有一些汽车,这些汽车需要到1号点,汽车只会走最短路,每条路同时只能有一辆汽车从一个方向进入(也就是说不同时候是可以进入的,不同方向互不影响),车的速度一定,问有几辆车能到达1号点。

题解

显然首先从1开始跑一次最短路。然后我们可以构造出一个最短路DAG出来(把非最短路上的边删去)。对于同一条边不能同时同向进入的问题,对于到1号点距离相同的车,必然是同时同向进入这些边的(如果不是的话就存在更优的最短路),因此对于这些距离相同的点我们构造一个流网络,1为汇点,这些距离相同的点连到源点,边容量为1,跑一次最大流就知道这些车能过去几辆。另外显然对于同一条边,不同距离的车是不会同时同向经过这条边的(到这条边的距离一定不一样)。至于数据范围的问题,dinic跑DAG的复杂度其实挺低的。。然后给了9s不慌。

好久没有写过150行的代码了。。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
#define FORD(i,j,k) for(i=j;i>=k;--i)
const int inf = 0x7FFFFFFF;
typedef long long ll;
const int N = 25005, M = 150005;

struct Graph {

    typedef pair<int, int> P;

    int h[N], cur[N], p[M], from[M], dis[N], to[M], w[M], del[M], edge;
    int s, t;

    Graph() { reset(); }

    void add(int a, int b, int c) {
        p[++edge] = h[a]; from[edge] = a; to[edge] = b; w[edge] = c; h[a] = edge;
    }

    void addNet(int a, int b, int c) {
        add(a, b, c);
        add(b, a, 0);
    }

    void reset() {
        memset(h, 0, sizeof h);
        edge = 1;
    }

    void removeUnusedEdges() {
        memset(del, 0, sizeof del);
        for (int i = 2; i <= edge; ++i)
            if (dis[to[i]] != dis[from[i]] + w[i])
                del[i] = 1;
    }

    template<typename _Iterator>
    void buildFrom(const Graph &g, _Iterator begin, _Iterator end) {
        for (int i = 2; i <= g.edge; ++i) {
            if (g.del[i]) continue;
            addNet(g.to[i], g.from[i], 1);
        }

        for (_Iterator it = begin; it != end; ++it)
            addNet(s, *it, 1);
    }

    void dijkstra(int s) {
        priority_queue<P, vector<P>, greater<P>> pq;
        memset(dis, 63, sizeof dis);
        dis[s] = 0;
        pq.push(P(dis[s], s));
        while (!pq.empty()) {
            P pa = pq.top(); pq.pop();
            int u = pa.second;
            if (pa.first > dis[u]) continue;
            for (int i = h[u]; i; i = p[i]) {
                if (dis[to[i]] > dis[u] + w[i]) {
                    dis[to[i]] = dis[u] + w[i];
                    pq.push(P(dis[to[i]], to[i]));
                }
            }
        }
    }

    bool bfs() {
        queue<int> q;
        int i, x;
        memset(dis, -1, sizeof dis);
        q.push(s); dis[s] = 0;
        while (!q.empty()) {
            x = q.front(); q.pop();
            for (i = h[x]; i; i = p[i])
                if (w[i] && dis[to[i]] == -1) {
                    dis[to[i]] = dis[x] + 1;
                    q.push(to[i]);
                }
        }
        return dis[t] != -1;
    }

    int dfs(int x, int low) {
        int i, tmp, res = 0;
        if (x == t) return low;
        for (i = cur[x]; i && res < low; i = p[i])
            if (w[i] && dis[to[i]] == dis[x] + 1) {
                tmp = dfs(to[i], min(low - res, w[i]));
                w[i] -= tmp; w[i ^ 1] += tmp; res += tmp;
                if (w[i]) cur[x] = i;
            }
        if (!res) dis[x] = -1;
        return res;
    }

    int dinic() {
        int ans = 0, i;
        while (bfs()) {
            memcpy(cur, h, sizeof h);
            ans += dfs(s, inf);
        }
        return ans;
    }
} root, g;

int c[N];

int comp(int x, int y) {
    return root.dis[x] < root.dis[y];
}

int main() {
    int n, m, k, x, y, l, t, ans = 0, i;

    scanf("%d%d%d", &n, &m, &k);

    rep(i,0,m) {
        scanf("%d%d%d", &x, &y, &t);
        root.add(x, y, t);
        root.add(y, x, t);
    }

    rep(i,0,k) scanf("%d", &c[i]);

    root.dijkstra(1);
    root.removeUnusedEdges();

    sort(c, c + k, comp);

    l = 0;
    FOR(i,1,k) {
        if (i != k && root.dis[c[i]] == root.dis[c[i - 1]])
            continue;

        if (i == l + 1) {
            ++ans;
        } else {
            g.reset();
            g.s = 0; g.t = 1;
            g.buildFrom(root, c + l, c + i);
            ans += g.dinic();
        }

        l = i;
    }

    printf("%d\n", ans);

    return 0;
}

D: Factors

题目大意

f ( k ) 表示k在质因数分解后的排列数,比如 f ( 20 ) = 3 ,因为 20 = 2 × 2 × 5 = 2 × 5 × 2 = 5 × 2 × 2 。已知 n ,求最小的 k 使得 f ( k ) = n

题解

考虑函数 f 的递推情况,首先可以肯定的是我们总是使用尽量小的质数去表示 k ,假设我们现在已经用前 m 1 小的质数 p 1.. m 表示了 k ,幂为 a 1.. m ,令 k = k × p m + 1 a m + 1 ,首先可以知道的是:

f ( k ) = ( i = 1 m a i ) ! i = 1 m a i !

s = i = 1 m a i

那么有:

(320) f ( k ) = ( i = 1 m + 1 a i ) ! i = 1 m + 1 a i ! (321) = s ! ( s + 1 ) ( s + 2 ) ( s + a m + 1 ) i = 1 m a i ! × a m + 1 ! (322) = s ! i = 1 m a i ! × ( s + 1 ) ( s + 2 ) ( s + a m + 1 ) a m + 1 ! (323) = f ( k ) × C s + a m + 1 p

因为题目已经限制 s , a i < 64 ,因此组合数可以预处理出来,那么 f ( k ) 就可以暴力求解,状态数不是很多。

遇到了坑。。无符号乘上有符号变成有符号整数。。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
#define FORD(i,j,k) for(i=j;i>=k;--i)
typedef unsigned long long ull;
const ull inf = 1ull << 63;

ull p[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67};

map<ull, ull> ans;
ull C[64][64];

void calcC() {
    int i, j;
    C[0][0] = 1;
    rep(i,1,64) {
        C[i][0] = 1;
        rep(j,1,64) {
            if (C[i - 1][j - 1] < inf && C[i - 1][j] < inf)
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
            else
                C[i][j] = inf;
        }
    }
}

void calc(ull k, ull n, int m, int s) {
    if (sum && (!ans.count(n) || ans[n] > k))
        ans[n] = k;

    ull k2 = k;
    for (int a = 1; p[m + 1] <= inf / k2; ++a) {
        k2 *= p[m + 1];
        calc(k2, n * C[s + a][s], m + 1, s + a);
    }
}

int main() {
    ull n;
    calcC();
    calc(1, 1, 0, 0);
    while (scanf("%llu", &n) == 1) {
        printf("%llu %llu\n", n, ans[n]);
    }
    return 0;
}

F: Low Power

题目大意

题解

二分

H: Matryoshka

题目大意

题解

巨恶心的dp,队友做的。。

J: Pollution Solution

题目大意

求一个多边形与半圆的面积交。

题解

半圆和圆没啥区别,所以当圆看就行了。
先将多边形分解为多个三角形,一个点在圆心,那么三角形与圆有4种情况,分别是两个点在圆内(直接算三角形面积),两个点在圆外(算扇形面积),一个点在圆外一个点在圆内(拆成一个三角形和一个扇形),两个点在圆外(但与圆交于2点,拆成2扇形和1个三角形)。

代码就不放了。。模板题。网上模板满天飞。

猜你喜欢

转载自blog.csdn.net/huanghongxun/article/details/79519745