Educational Codeforces Round 38 [Codeforces938]

16 篇文章 0 订阅
7 篇文章 0 订阅

题目链接
官方题解

A. Word Correction

题目大意

a,e,i,o,u,y a , e , i , o , u , y 是六个特殊字母,如果一个小写字母串从左往右读,出现连续两个特殊字母时,则删除后面这个特殊字母,直至没有连续两个特殊字母,输出这样处理后的字符串。

思路 - 模拟

按照题意模拟即可: i i 表示将要输出的字母,j表示下一个可能会输出的字母
①如果 i,j i , j 都是特殊字母,则 i i 不变,令j变为下一个字母
②如果 i,j i , j 至少有一个不是特殊字母,则输出 i i ,然后令i=j j j 变为下一个字母

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 103;

int n;
char s[MAXN];

inline bool isVowel(char ch) {
    return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'y';
}

int main() {
    while(2 == scanf("%d%s", &n, s)) {
        for(int i = 0, j = 1; i < n;) {
            if(isVowel(s[i]) && isVowel(s[j])) {
                ++j;
            }
            else {
                printf("%c", s[i]);
                i = j;
                if(j < n) {
                    ++j;
                }
            }
        }
        printf("\n");
    }
}

B. Run For Your Prize

题目大意

在一条数轴上坐标为21061范围内有 n n 个奖品,甲可以从坐标为1的位置开始拿奖品,乙可以从坐标为 106 10 6 的位置开始拿奖品,两人每移动一个单位距离需要 1 1 秒,拿奖品不耗时,求两人把所有奖品拿完的最短耗时?

思路 - 模拟

枚举相邻的两个奖品(左边分别为i,j),甲拿前者及其左边的奖品,乙拿后者及其右边的奖品,则总耗时为 max(i1,106j) m a x ( i − 1 , 10 6 − j ) ,取最小值。注意边界值,及甲或者乙不拿奖品的时候。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int END = 1e6;

int n;
int last, cur, ans;

int main() {
    while(1 == scanf("%d", &n)) {
        ans = END;
        last = 0;
        while(n-- > 0) {
            scanf("%d", &cur);
            ans = min(ans, max(END - cur, last - 1));
            last = cur;
        }
        ans = min(ans, last - 1);
        printf("%d\n", ans);
    }
}

C. Constructing Tests

题目大意

设一个 n n 01方阵,若其每一个 m m 阶子方阵内都至少含有一个0,此时这个 n n 阶方阵内最多能有k 1 1 。现在给定k,构造 n,m n , m 使其满足上述条件,无法构造则输出 1 − 1

思路 - 枚举

用将 n n 阶方阵划分成不重叠的m阶方阵,不够的不计算,则共能划分成 nm2 ⌊ n m ⌋ 2 个完整的 m m 阶方阵,每个方阵右下角取0,其全为 1 1 ,则能满足题意。从而得到关系:n2nm2=k
又: m=1 m = 1 时, k k 横为0,且 n n 不变时,k随着 m m 的递增而非递减,可知对于每一个n k k 的下界为3n24,从而由 k k 得到n的上界为 4k3 4 k 3 ,所以枚举 n n ,然后计算得m,再判断 n,m,k n , m , k 是否满足得到的关系即可。

代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const double EPS = 1e-6;

int x;

int main() {
    int T;
    scanf("%d", &T);
    while(T-- > 0) {
        scanf("%d", &x);
        if(x == 0) {
            printf("1 1\n");
            continue;
        }
        bool flag = false;
        for(int n = 2; ((3LL * n * n) >> 2LL) <= x; ++n) {
            long long tmp = 1LL * n * n - x;
            if(tmp > 0) {
                int n_m = sqrt(tmp) + EPS;
                int m = n / n_m;
                if(n * n - (n / m) * (n / m) == x) {
                    printf("%d %d\n", n, m);
                    flag = true;
                    break;
                }
            }
        }
        if(!flag) {
            printf("-1\n");
        }
    }
}

D. Buy a Ticket

题目大意

给定一个 n n 个顶点,m条边的无向图,每条边都有权值 w w ,每个顶点有权值a,对于每一个顶点 i i 找出一个顶点j i i j的最短路径为 dist d i s t j j 的权值为x),使得: 2dist+x 2 d i s t + x 最小。

思路 - Dijkstra

设置一个超级源点,其到每个顶点都有条无向边,权值为该顶点的权值,则问题转化为单元最短路,直接用堆优化的 Dijkstra D i j k s t r a 即可。

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int MAXN = 200003;
const int MAXM = 200003;

struct Node {
    int v;
    long long w;

    Node() {}

    Node(int v, long long w):v(v), w(w) {}

    bool operator< (const Node& a) const {
        return w > a.w;
    }
};

struct Edge {
    int v, nxt;
    long long w;
}edge[(MAXM + MAXN) << 1];

int tot, fir[MAXN];

void init() {
    tot = 0;
    memset(fir, -1, sizeof(fir));
}

void addEdge(int u, int v, long long w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = fir[u];
    fir[u] = tot++;

    edge[tot].v = u;
    edge[tot].w = w;
    edge[tot].nxt = fir[v];
    fir[v] = tot++;
}

int n, m;
long long a;
long long dist[MAXN];
bool vis[MAXN];

void dijkstra() {
    memset(vis, false, sizeof(vis));
    memset(dist, 0x3f, sizeof(dist));
    dist[0] = 0;
    priority_queue<Node> q;
    q.push(Node(0, dist[0]));

    int u, v;
    long long w;
    Node cur;
    while(!q.empty()) {
        cur = q.top();
        u = cur.v;
        w = cur.w;
        q.pop();
        if(vis[u]) {
            continue;
        }
        vis[u] = true;

        for(int i = fir[u]; i != -1; i = edge[i].nxt) {
            v = edge[i].v;
            w = edge[i].w;
            if(dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                q.push(Node(v, dist[v]));
            }
        }
    }
}

int main() {
    int u, v;
    long long w;
    while(2 == scanf("%d%d", &n, &m)) {
        init();
        while(m-- > 0) {
            scanf("%d%d%I64d", &u, &v, &w);
            addEdge(u, v, w << 1LL);
        }
        for(int i = 1; i <= n; ++i) {
            scanf("%I64d", &a);
            addEdge(0, i, a);
        }
        dijkstra();
        for(int i = 1;i <= n; ++i) {
            printf("%I64d%c", dist[i], i == n ? '\n' : ' ');
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值