Codeforces Round #364 (Div. 2)

A
题意: n个数,两两配对,要求配对后的和相等。保证存在方案。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e6 + 1;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
int a[110];
vector<int> G[110];
bool vis[110];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        int sum = 0;
        for(int i = 1; i <= 100; i++) {
            G[i].clear(); vis[i] = false;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum += a[i];
            G[a[i]].push_back(i);
        }
        int ave = 2 * sum / n;
        for(int i = 1; i <= n; i++) {
            if(vis[i]) continue;
            vis[i] = true;
            int val = ave - a[i];
            for(int j = 0; j < G[val].size(); j++) {
                int id = G[val][j];
                if(vis[id]) continue;
                else {
                    printf("%d %d\n", i, id);
                    vis[id] = true;
                    break;
                }
            }
        }
    }
    return 0;
}

B
题意:n * n的格子,位置(i,j)的士兵可以攻击到第i行和第j列的所有位置。现在要放m个士兵,问你前i个士兵不能攻击到的位置总数。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 1;
const int MAXM = 1e6 + 1;
const int INF = 1e9 + 10;
bool row[MAXN], cul[MAXN];
LL ans[MAXN];
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++) {
            row[i] = cul[i] = false;
        }
        LL num = 1LL * n * n;
        int nrow = 0, ncul = 0;
        for(int i = 1; i <= m; i++) {
            int x, y; scanf("%d%d", &x, &y);
            if(!row[x]) {
                num = num - n + ncul;
            }
            if(!cul[y]) {
                num = num - n + nrow;
            }
            if(!row[x] && !cul[y]) {
                num++;
                nrow++; ncul++;
                row[x] = true;
                cul[y] = true;
            }
            else if(!row[x]) {
                nrow++;
                row[x] = true;
            }
            else if(!cul[y]) {
                ncul++;
                cul[y] = true;
            }
            ans[i] = num;
        }
        for(int i = 1; i <= m; i++) {
            if(i > 1) printf(" ");
            printf("%lld", ans[i]);
        }
        printf("\n");
    }
    return 0;
}

C

题意:给定一个字符串,问你最短的子串覆盖出现的所有字符。

尺取 or 二分

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 1;
const int MAXM = 1e6 + 1;
const int INF = 1e9 + 10;
char str[MAXN];
int sum1[MAXN][30], sum2[MAXN][30];
bool vis1[30], vis2[30];
bool Check(int L, int R) {
    for(int i = 0; i <= 25; i++) {
        if(vis1[i]) {
            if(sum1[R][i] - sum1[L-1][i] < 1) return false;
        }
        if(vis2[i]) {
            if(sum2[R][i] - sum2[L-1][i] < 1) return false;
        }
    }
    return true;
}
int n;
bool judge(int o) {
    for(int i = 1; i + o - 1 <= n; i++) {
        if(Check(i, i + o - 1)) return true;
    }
    return false;
}
int main()
{
    while(scanf("%d", &n) != EOF) {
        scanf("%s", str + 1);
        for(int i = 0; i <= 25; i++) {
            sum1[0][i] = sum2[0][i] = 0;
            vis1[i] = vis2[i] = false;
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j <= 25; j++) {
                sum1[i][j] = sum1[i-1][j];
                sum2[i][j] = sum2[i-1][j];
            }
            if(str[i] >= 'a' && str[i] <= 'z') {
                int v = str[i] - 'a';
                sum1[i][v]++;
                vis1[v] = true;
            }
            else {
                int v = str[i] - 'A';
                sum2[i][v]++;
                vis2[v] = true;
            }
        }
        int l = 1, r = n, ans;
        while(r >= l) {
            int mid = (l + r) >> 1;
            if(judge(mid)) {
                ans = mid;
                r = mid - 1;
            }
            else {
                l = mid + 1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

D

题意:n个人从0位置到L位置,步行速度v1,乘车速度v2。每趟车只能载k个人,每个人只能坐一次车,问所有人到达L位置的最短时间。

思路:YY最优情况下,每个人步行、乘车距离是相等的。
发现每个上车点到下一个上车点的距离是一定的,这样我们依次求出每个上车位置。
设最后一个上车位置为d,d就是步行距离,乘车距离 = L - d。
然后时间 = d / v1 + (L - d) / v2。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <string>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) {x += y; x %= MOD;}
int main()
{
    int n, l, v1, v2, k;
    while(scanf("%d%d%d%d%d", &n, &l, &v1, &v2, &k) != EOF) {
        int m = n % k == 0 ? n / k : n / k + 1;
        double l1 = (2.0 * (m - 1) * l * v1) / ((v2 - v1) * 1.0 + 2.0 * m * v1);
        double l2 = l * 1.0 - l1;
        printf("%.10lf\n", l1 / v1 + l2 / v2);
    }
    return 0;
}

E

题意:给定一棵树和k对点,问你这k对点两两匹配后各自距离之和的最大值。

思路:因为是一棵树,把这k对点连接起来的路径是唯一的。也就是说,我们只需要统计这个路径上每条边被覆盖多少次即可。
显然对于第i条边u -> v,若v上面有x个点,下面有y个点,这些点两两匹配的缘故这条边肯定要被覆盖min(x, y)次,因此我们只需要DFS一次统计贡献就好了。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <string>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 2 * 1e5 + 10;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) {x += y; x %= MOD;}
int n, k;
LL ans;
vector<int> G[MAXN];
int num[MAXN];
void DFS(int u, int fa) {
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(v == fa) continue;
        DFS(v, u);
        num[u] += num[v];
        ans += min(num[v], k - num[v]);
    }
}
int main()
{
    while(scanf("%d%d", &n, &k) != EOF) {
        k <<= 1;
        for(int i = 1; i <= n; i++) num[i] = 0, G[i].clear();
        for(int i = 1; i <= k; i++) {
            int u; scanf("%d", &u);
            num[u] = 1;
        }
        for(int i = 0; i < n - 1; i++) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        ans = 0; DFS(1, -1);
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值