ComWin’ round 11部分题解

https://vjudge.net/contest/325913#overview

A.Threehouses

题意:一直二维平面上的$n$个点中,前$e$个点落在小岛周围,并且有$p$条边已经连接,问最少花费使得所有点都可以通过一些边到达小岛,两点之间建边的花费为两点间的欧式距离。

思路:根据$kruskal$求最小生成树的方法将前$e$个点合并起来,再将已有$p$条边的两点合并,之后做一次$kruskal$把所有点合并即可。

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1000 + 10;

int fa[maxn];
double x[maxn], y[maxn], dist[maxn][maxn];
int tot;
struct node {
    int u, v;
    double val;
    bool operator < (const node &rhs) const {
        return val < rhs.val;
    }
}edge[maxn * maxn];

int fr(int x) {
    if(fa[x] == x) return x;
    return fa[x] = fr(fa[x]);
}
void uni(int x, int y) {
    x = fr(x), y = fr(y);
    if(x != y) fa[x] = y;
}
void init(int n) {
    tot = 0;
    for(int i = 0; i <= n; i++) {
        fa[i] = i;
    }
}
double cal(int i, int j) {
    double ret = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
    return ret;
}
int main() {
    int n, e, p;
    scanf("%d%d%d", &n, &e, &p);
    init(n + 1);
    for(int i = 1; i <= n; i++) {
        scanf("%lf%lf", &x[i], &y[i]);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++) {
            dist[i][j] = dist[j][i] = cal(i, j);
            node now;
            now.u = i, now.v = j, now.val = dist[i][j];
            edge[tot++] = now;
        }
    }
    sort(edge, edge + tot);
    for(int i = 1; i <= e; i++) {
        uni(0, i);
    }
    double ans = 0.0;
    for(int i = 0; i < p; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        uni(u, v);
    }
    for(int i = 0; i < tot; i++) {
        node now = edge[i];
        int fu = fr(now.u), fv = fr(now.v);
        if(fu != fv) {
            ans += now.val;
            fa[fu] = fv;
        }
    }
    printf("%.6f\n", ans);
    return 0;
}

C.Cops ans Robbers

题意:给定图中只有字母点可以设立障碍,问让小偷所在的位置$B$无法达到边界所需设立障碍的最小花费。

思路:先说做法。考虑最小割,对每个点拆点,让$u$到$u^{‘}$的流量为该点对应的值,如果该点不能设立障碍则为$inf$,然后对一个点$u$的相邻点连一条$u^{‘}$到$v$流量为$inf$的边,如果越界那么就连向汇点$T$,流量依旧为$inf$。这样做使得每个格点所在的路径流向$T$的最小割只会被其上的价值最小的点所限制,由于建图时所有相邻格点都有连边,所以从源点出发时不会漏边。

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1000 + 5;
const int inf = 0x3f3f3f3f;
const LL linf = 0x3f3f3f3f3f3f3f3f;

int n, m, c, T;
LL val[26];
char mp[N][N];
struct Dinic {
    static const int maxn = 1e6 + 5;
    static const int maxm = 4e6 + 5;

    struct Edge {
        int u, v, next;
        LL flow, cap;
    } edge[maxm];

    int head[maxn], level[maxn], cur[maxn], eg;

    void addedge(int u, int v, LL cap) {
        edge[eg] = {u, v, head[u], 0, cap}, head[u] = eg++;
        edge[eg] = {v, u, head[v], 0, 0}, head[v] = eg++;
    }

    void init() {
        eg = 0;
        memset(head, -1, sizeof head);
    }

    bool makeLevel(int s, int t, int n) {
        for(int i = 0; i < n; i++) level[i] = 0, cur[i] = head[i];
        queue<int> q; q.push(s);
        level[s] = 1;
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for(int i = head[u]; ~i; i = edge[i].next) {
                Edge &e = edge[i];
                if(e.flow < e.cap && level[e.v] == 0) {
                    level[e.v] = level[u] + 1;
                    if(e.v == t) return 1;
                    q.push(e.v);
                }
            }
        }
        return 0;
    }

    LL findpath(int s, int t, LL limit = linf) {
        if(s == t || limit == 0) return limit;
        for(int i = cur[s]; ~i; i = edge[i].next) {
            cur[edge[i].u] = i;
            Edge &e = edge[i], &rev = edge[i^1];
            if(e.flow < e.cap && level[e.v] == level[s] + 1) {
                LL flow = findpath(e.v, t, min(limit, e.cap - e.flow));
                if(flow > 0) {
                    e.flow += flow;
                    rev.flow -= flow;
                    return flow;
                }
            }
        }
        return 0;
    }

    LL max_flow(int s, int t, int n) {
        LL res = 0;
        while(makeLevel(s, t, n)) {
            LL flow;
            while((flow = findpath(s, t)) > 0) {
                if(res >= linf) return res;
                res += flow;
            }
        }
        return res;
    }
} di;

int id(int r, int c) {
    if(r < 1 || r > n || c < 1 || c > m) return T;
    return (r - 1) * m + c;
}

LL getVal(int r, int c) {
    if(r < 1 || r > n || c < 1 || c > m) return linf;
    if(mp[r][c] == ‘.‘ || mp[r][c] == ‘B‘) return linf;
    else return val[mp[r][c] - ‘a‘];
}

int main() {
    scanf("%d%d%d", &m, &n, &c);
    for(int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    for(int i = 0; i < c; i++) scanf("%lld", &val[i]);
    T = 2*n*m + 5;
    di.init();
    di.addedge(id(1, 1) + n*m, T, linf);
    di.addedge(id(1, m) + n*m, T, linf);
    di.addedge(id(n, 1) + n*m, T, linf);
    di.addedge(id(n, m) + n*m, T, linf);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            di.addedge(id(i, j), id(i, j) + n*m, getVal(i, j));
            if((i == 1 || i == n) && (j == 1 || j == m)) continue;
            di.addedge(id(i, j) + n*m, id(i+1, j), linf);
            di.addedge(id(i, j) + n*m, id(i-1, j), linf);
            di.addedge(id(i, j) + n*m, id(i, j+1), linf);
            di.addedge(id(i, j) + n*m, id(i, j-1), linf);
        }
    }
    LL ans = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(mp[i][j] == ‘B‘) {
                ans = di.max_flow(id(i, j), T, T+10);
            }
            if(ans) break;
        }
        if(ans) break;
    }
    printf("%lld\n", ans >= linf ? -1 : ans);
    return 0;
}
/*
10 10 1
..........
..........
..........
...a.a....
..a.a.a...
.a..B.a...
..aaaaa...
..........
..........
..........
1
*/

E.Coprime Integers

题意:给定$a,b,c,d$,求$\sum_{i=a}^{b}\sum_{j=c}^{d}[gcd(i,j)=1]$,$[t=1]$表示$t$等于$1$时的值为$1$,否则为$0$。

思路:容斥原理+莫比乌斯反演,考虑$solve(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=1]$,可以发现$ans=solve(b,d)-solve(a-1,d)-solve(c-1,b)+solve(a-1,c-1)$。接着考虑如何计算$solve(n,m)$

$\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=1]$

$=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{t|i,t|j}u(t)$

$=\sum_{t=1}^{min(n,m)}u(t)\sum_{i=1}^{\left \lfloor \frac{n}{t} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{t} \right \rfloor}1$

$=\sum_{t=1}^{min(n,m)}u(t)\left \lfloor \frac{n}{t} \right \rfloor\left \lfloor \frac{m}{t} \right \rfloor$

预处理莫比乌斯函数前缀和之后整除分块即可在$O(\sqrt n)$复杂度内求出一次$solve$。

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1e7 + 5;

int p[N / 10], cnt, mu[N];
bool tag[N];

void getPrime() {
    mu[1] = 1;
    for(int i = 2; i < N; i++) {
        if(!tag[i]) {
            mu[i] = -1;
            p[cnt++] = i;
        }
        for(int j = 0; j < cnt && 1LL * p[j] * i < N; j++) {
            tag[i * p[j]] = 1;
            if(i % p[j] == 0) {
                mu[i * p[j]] = 0;
                break;
            }
            mu[i * p[j]] = -mu[i];
        }
    }
    for(int i = 1; i < N; i++) mu[i] += mu[i - 1];
}

LL solve(LL n, LL m) {
    LL res = 0;
    for(LL l = 1, r; l <= min(n, m); l = r + 1) {
        r = min(n / (n / l), m / (m / l));
        res += (mu[r] - mu[l - 1]) * (n / l) * (m / l);
    }
    return res;
}

int main() {
    getPrime();
    LL a, b, c, d;
    scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
    printf("%lld\n", solve(b, d) - solve(a - 1, d) - solve(c - 1, b) + solve(a - 1, c - 1));
    return 0;
}

H.Heir‘s Dilemma

题意:求$L$到$H$之间满足位数是$6$位,且没有某一位是$0$,且能被每一位的数字整除的数的个数。

思路:数据范围很小,暴力枚举每个数$check$是否可行即可。

#include <bits/stdc++.h>

using namespace std;

bool ck(int x) {
    bool vis[10];
    for(int i = 0; i < 10; i++) vis[i] = false;
    int xx = x, xxx = x, xxxx = x;
    while(xxx) {
        if(xxx % 10 == 0) return false;
        xxx /= 10;
    }
    while(xxxx) {
        if(vis[xxxx % 10] == true) return false;
        vis[xxxx % 10] = true;
        xxxx /= 10;
    }
    while(xx) {
        int now = xx % 10;
        if(x % now != 0) return false;
        xx /= 10;
    }
    return true;
}

int main() {
    int cnt = 0, a, b;
    cin >> a >> b;
    for(int i = a; i <= b; i++) cnt += (int)ck(i);
    cout << cnt << endl;
}

原文地址:https://www.cnblogs.com/DuskOB/p/11517554.html

时间: 2024-08-05 10:23:15

ComWin’ round 11部分题解的相关文章

BestCoder Round #11 (Div. 2) 前三题题解

题目链接: huangjing hdu5054 Alice and Bob 思路: 就是(x,y)在两个參考系中的表示演全然一样.那么仅仅可能在这个矩形的中点.. 题目: Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 216    Accepted Submission(s): 166 Problem De

BestCoder Round #11 (Div. 2) 题解

HDOJ5054 Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 302    Accepted Submission(s): 229 Problem Description Bob and Alice got separated in the Square, they agreed that if they

BestCoder Round #11 (Div. 2)题解集合

Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 155    Accepted Submission(s): 110 Problem Description Bob and Alice got separated in the Square, they agreed that if they get sepa

PA 2011 Round 3 prz题解

题目大意,现在要走过一条斑马线,斑马线是由n条交替的黑条和白条构成的,第一条是黑条.脚的长度是s.要求在走的过程中,他脚的任何一部分都不能碰到象征邪恶的黑条.第一条之前和第n条之后的部分都是白色的,可以任意选择第一条之前的位置出发.但出发位置一旦选定,之后每一步的长度都必须是k.请你判断有没有可能在不碰到黑条的情况下通过斑马线,即走到第n条之后. 此题同样是模拟赛题!!! 我现在已经非常质疑自己的智商了,为什么每次都是离正解只差一步呢,每次都不能换一个思路去想一想. 先说说我的错误解法:我列了n

POJ 3252 Round Numbers 数学题解

Description The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names) in order to make arbitrary decisions such as who gets

Math.round(11.5)等于多少? Math.round(-11.5)等于多少?

1.先说下怎么理解 round()方法可以这样理解: 将括号内的数+0.5之后,向下取值, 比如:round(3.4)就是3.4+0.5=3.9,向下取值是3,所以round(3.4)=3; round(-10.5)就是-10.5+0.5=-10,向下取值就是-10,所以round(-10.5)=-10 所以,Math.round(11.5)=12; 现在再来看,Math.round(11.5),Math.round(-11.5)你应该知道等于多少了吧,掌握了方法就好解决问题了. 这个题面试了很

int和integer;Math.round(11.5)和Math.round(-11.5)

int是java提供的8种原始数据类型之一.Java为每个原始类型提供了封装类,Integer是java为int提供的封装类.int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer.在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字符串,而int默认的默认值为0,所以用el表达式在文本框中显示时,结果

Educational Codeforces Round 64部分题解

Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点个数是否有限,如果有限,输出. 很明显当正方形套三角形或者三角形套正方形是交点个数是无限的(因为有一条边相交) 其他图形的嵌套交点个数比较好判断,不多赘述 但是注意坑点: 当按照矩形,园,三角这样的顺序是,三角与圆的一个交点是与圆和正方形的交点重合的,判一下就好了 #include<cstdio>

BestCoder Round #11 题解集合

1001.Alice and Bob 签到题*1,只要x * 2 == n && y * 2 == m就满足条件. 1 var 2 m, n, x, y : int64; 3 4 begin 5 while not eof do begin 6 readln(m, n, x, y); 7 if (m = 2 * x) and (n = 2 * y) then writeln('YES') else writeln('NO'); 8 end; 9 end. 1002.Bob and math