Codeforces Round #365 (Div. 2)

本文提供了三道算法竞赛题目的解答思路及代码实现,包括图论问题、几何问题和区间查询问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

懒得吐槽了。
A
水的不能再水了。
B
题意:n个成环的点,有k个特殊点和其它每个点都有一条边。已知任意两个点之间最多1条边,边权是这两个点权值乘积,问所有边权之和。
分别处理特殊点和非特殊点统计一下就好了。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int INF = 1e9 + 10;
const int MOD = 110119;
void add(LL &x, LL y) { x += y; x %= MOD; }
int c[MAXN], a[MAXN];
bool vis[MAXN];
int main()
{
    int n, k;
    while(scanf("%d%d", &n, &k) != EOF) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &c[i]);
            vis[i] = false;
        }
        LL sum2 = 0;
        for(int i = 1; i <= k; i++) {
            scanf("%d", &a[i]);
            sum2 += c[a[i]];
            vis[a[i]] = true;
        }
        LL ans = 0;
        for(int i = 1; i <= n; i++) {
            int next = i + 1;
            if(next > n) {
                next = 1;
            }
            if(vis[i]) continue;
            if(!vis[next]) {
                ans += 1LL * c[i] * sum2 + 1LL * c[i] * c[next];
            }
            else {
                ans += 1LL * c[i] * sum2;
            }
        }
        for(int i = 1; i <= n; i++) {
            if(vis[i]) {
                ans += 1LL * c[i] * (sum2 - c[i]);
                sum2 -= c[i];
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

C
题意:一个汽车向x轴负向开,一个人从原点向(0,y)点走,给你这个汽车的形状(一个凸多边形),问你这个人最少需要多长时间可以到达目的地且不被车撞倒。
思路:考虑每个点x - v * t = d,d > 0,u * t = y。这样d = x - y / u * v。
我们统计一下最大的d和最小的d讨论一下即可。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e6 + 10;
const int INF = 1e9 + 10;
const int MOD = 110119;
void add(LL &x, LL y) { x += y; x %= MOD; }
int main()
{
    int n, w, u, v;
    while(scanf("%d%d%d%d", &n, &w, &v, &u) != EOF) {
        double Min = 2e9;
        double Max = 0;
        for(int i = 0; i < n; i++) {
            int x, y; scanf("%d%d", &x, &y);
            Min = min(Min, x * 1.0 - y * 1.0 / u * v);
            Max = max(Max, x * 1.0 - y * 1.0 / u * v);
        }
        if(Min >= 0) {
            printf("%.10lf\n", w * 1.0 / u);
        }
        else {
            printf("%.10lf\n", Max / v + w * 1.0 / u);
        }
    }
    return 0;
}

D
题意:问你区间里面出现偶数次的元素异或和。
ZZ,看错数据范围,直接莫队开搞,T了一发才发现多了一个0。浪费那么长时间才过,真的ZZ。
思路:转化问题,记区间出现不同元素异或和为sum1,区间元素异或和为sum2,那么结果显然为sum1 ^ sum2。我们只要快速求出区间不同元素异或和即可。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e6 + 10;
const int INF = 1e9 + 10;
const int MOD = 110119;
void add(LL &x, LL y) { x += y; x %= MOD; }
struct Node {
    int l, r, id;
};
Node num[MAXN];
bool cmp(Node a, Node b) {
    return a.r < b.r;
}
LL C[MAXN];
map<int, int> lp;
int lowbit(int x) {
    return x & (-x);
}
int n;
void add(int x, LL d) {
    while(x <= n) {
        C[x] ^= d;
        x += lowbit(x);
    }
}
LL Sum(int x) {
    LL s = 0;
    while(x > 0) {
        s ^= C[x];
        x -= lowbit(x);
    }
    return s;
}
LL a[MAXN], ans[MAXN], sum[MAXN];
int main()
{
    while(scanf("%d", &n) != EOF) {
        lp.clear(); sum[0] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum[i] = sum[i-1] ^ a[i];
        }
        int m; scanf("%d", &m);
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &num[i].l, &num[i].r);
            num[i].id = i;
        }
        sort(num + 1, num + m + 1, cmp);
        memset(C, 0, sizeof(C)); int j = 1;
        for(int i = 1; i <= m; i++) {
            while(j <= num[i].r) {
                if(!lp[a[j]]) {
                    add(j, a[j]);
                }
                else {
                    add(lp[a[j]], a[j]);
                    add(j, a[j]);
                }
                lp[a[j]] = j; j++;
            }
            ans[num[i].id] = Sum(num[i].r) ^ Sum(num[i].l - 1) ^ sum[num[i].r] ^ sum[num[i].l-1];
        }
        for(int i = 1; i <= m; i++) {
            printf("%lld\n", ans[i]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值