Codeforces Round #703 (Div. 2) A、B、D、E题解

写在前边

链接:Codeforces Round #703 (Div. 2)
这次的交互题是真不会做。

A. Shifting Stacks

链接:A题链接

题目大意:

n摞高度分别为hi的山,现在我们可以从每次从第i座山移动高度为1的移到i+1座山上,问是否可以形成一个严格单调递增的山脉。

思路

贪心的想我们一直挪山,让第一座山高度为0,第二座山高度为1,第三座山高度为为2,依次类推就可以了,这样形成1,2,3,...,i座山的总需要的高度就是need=i(i1)2, 所以我们对于枚举到的每一座山只需要判断目前拥有的高度k=1ih[k]是否能构造出need即可,即k=1ih[k]>i(i1)2

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 110;
LL h[N];

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%lld", &h[i]);
    LL sum = 0, need = 0;
    for (int i = 0; i < n; i++) {
        need += i;
        sum += h[i];
        if (sum < need) {
            puts("NO");
            return;
        }
    }
    puts("YES");
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    scanf("%d", &t); 
    while (t--) {
        solve();
    }

    return 0;
}

B. Eastern Exhibition

链接:B题链接

题目大意:

给定一堆(xy),两点距离定义为|x2x1|+|x2x1|,现在需要选取有多少个点到每个点之和最小。

思路

首先想到|x2x1||x2x1|坐标的距离互不影响,于是就可以转化成先求一维,然后利用乘法原理相乘就是结果。
对于一维,就是经典的货仓选址了,排个序,对于奇数个点,那么就中位数唯一,如果是偶数,那么可以选择两个中位数以及之间任意位置即可,即[n2,n2+1]

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 1010;
int x[N], y[N];

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &x[i], &y[i]);
    }
    sort(x + 1, x + n + 1);
    sort(y + 1, y + n + 1);
    if (n & 1) puts("1");
    else {
        int calx = x[n / 2 + 1] - x[n / 2] + 1, caly = y[n / 2 + 1] - y[n / 2] + 1;
        printf("%lld\n", (LL) calx * caly);
    }
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    scanf("%d", &t); 
    while (t--) {
        solve();
    }

    return 0;
}

D. Max Median

链接:D题链接

题目大意:

给定一个数组长度为n的数组a,求长度为至少k的子数组的最大中位数。

思路

参考博客:随处可见的阿宅
枚举一个最大的中位数明显可以用二分来优化,然后再检查其合理性,二分枚举一个x,检查其合理性即检查它是否为中位数的时候可以有一个技巧,即构造一个序列,让x的数
1,让x的数为1,那么这样来说,如果某一长度至少为k子段和大于0,那么x就是这个子段的中位数,很神奇,那么这里可以用前缀和优化,剩下的就是枚举长度至少为k的前缀和了,所以剩下的任务就是找一个ik以及j[1,ik],且满足s[i]s[j]>0,而对于s[j]我们仅需要维护那个最小的前缀即可。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 2e5 + 10;
int a[N], b[N], minpref[N]; 
int n, k;

bool check(int x) {
    for (int i = 1; i <= n; i++) b[i] = (a[i] >= x ? 1 : -1);
    for (int i = 1; i <= n; i++) b[i] += b[i - 1];
    for (int i = 1; i <= n; i++) minpref[i] = min(minpref[i - 1], b[i]);
    for (int i = k; i <= n; i++) {
        if (b[i] - minpref[i - k] > 0) return true;
    }
    return false;
}

void solve() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

    int l = 1, r = n + 1;
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    
    printf("%d\n", l);
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    solve();

    return 0;
}

E - Paired Payment

链接:E题链接

题目大意:

最短路问题,只不过是一次只能走两步,不能一次一步走,比如a->b->c,那么就是a->c,花费是(wab+wbc)2

思路

参考博客:随处可见的阿宅
两天了,终于悟了,其实暴力跑单源最短路就可以,比如从a>b>c (a,b,c指点集,不是具体的点),那么就是从a搜到最短的b,然后再从b搜到最短的c,就是两重循环,然后看大佬一个很重要的优化就是,当b作为中间点的时候,我们可以维护一个a>b的最短路径,这样由于边权最大就是50,所以最坏情况下更新次数也不会超过50的,那么这题就终于这么过了。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
#include <queue>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 1E5 + 10, M = 4 * N;
int h[N], e[M], ne[M], w[M], idx;
int dist[N], mindist[N];
bool st[N];

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void Dijkstra() {
    priority_queue<PII, vector<PII>, greater<PII> > heap;
    heap.push({0, 1});
    memset(dist, 0x3f, sizeof dist), memset(mindist, 0x3f, sizeof mindist);
    dist[1] = 0;

    while (heap.size()) {
        auto t = heap.top();
        heap.pop();
        int var = t.second, cost = t.first;
        
        if (st[var]) continue;
        st[var] = true;

        for (int i = h[var]; i != -1; i = ne[i]) {
            int var1 = e[i], cost1 = w[i];
            if (mindist[var1] > cost1) {
                for (int j = h[var1]; j != -1; j = ne[j]) {
                    int var2 = e[j], cost2 = w[j];
                    if (dist[var2] > (cost2 + cost1) * (cost2 + cost1) + cost) {
                        dist[var2] = (cost2 + cost1) * (cost2 + cost1) + cost;
                        heap.push({dist[var2], var2});
                    }
                }
                mindist[var1] = cost1;
            }
        }
    }
}

void solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c), add(b, a, c);
    }

    Dijkstra();

    for (int i = 1; i <= n; i++) {
        if (dist[i] == 0x3f3f3f3f) printf("%d ", -1);
        else printf("%d ", dist[i]);
    }
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    solve();
    return 0;
}
posted @   Xxaj5  阅读(144)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示