当前位置:网站首页>题解:Edu Codeforces 109(div2)

题解:Edu Codeforces 109(div2)

2022-08-09 20:51:00 Here_SDUT

题目链接

A. Potion-making

题意

告诉你需要配置药剂的浓度k%,药剂由水和药混合而成,让你找到药剂最小的剂量,满足浓度为k%,浓度计算方法:药的体积/药剂总体积。

分析

设药的体积为a,水的体积为b,则\frac{1-k}{k} = \frac{b}{a},那么要求a+b最小,即求一下1-k和k的最大公约数g,答案就是\frac{1-k}{g} + \frac{k}{g}

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;

int main(int argc, char const *argv[]) {
    int t;
    cin  >> t;
    while(t--) {
        int k;
        cin >> k;
        int a = k, b = 100-k;
        int tt = __gcd(a,b);
        a/= tt, b/=tt;
        cout << a + b <<endl;
    }
    return 0;
}

B. Permutation Sort

题意

给你一个1-n的排列,有一个操作:将排列的某个连续区间内的数字调整次序,但是不能选择整个排列作为区间,问最少需要几次调整可以将一个排列变成升序的。

分析

有四种情况:

  • 初始状态已经是升序:需要0次。
  • 初始时1在最左端或者n在最右端,则需要1次调整即可变成升序。
  • 初始时1在最右端并且n在最左端,发现无论如何都需要3多次才行。
  • 剩下的情况都只要两次调整即可,因为最大值和最小值在内部。

分别判断即可。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
int a[111];
int main(int argc, char const *argv[]) {
    int t;
    cin  >> t;
    while(t--) {
       int n;
       cin >> n;
       int f = 1;
       for(int i = 1; i <= n; i++) {
           cin >> a[i];
           if(a[i] != i) f = 0;
       }
       if(f == 1) puts("0");
       else if(a[1] == 1 || a[n] == n) puts("1");
       else if(a[1] == n && a[n] == 1) puts("3");
       else puts("2");
    }
    return 0;
}

C. Robot Collisions(思维+贪心+模拟)

题意

一个数轴上的某些点上有机器人,保证一个点上不会有多个机器人,每个机器人的速度都是1,给出机器人的初始方向L或R,坐标为0和m的地方是一堵墙,机器人碰到墙后立马掉头。两个机器人如果在整数坐标点相遇则两个机器人消失,问所有机器人消失的时间,如果不会消失则用-1代替。

分析

对于每对机器人(假设左边的机器人坐标为x_1,右边的为x_2)一共有四种情况:

(1)RL:左边的向右,右边的向左走,下同,则相遇时间为\frac{x_2-x_1}{2}

(2)RR:相遇时间为 m-\frac{x_2+x_1}{2}

(3)LL:相遇时间为 \frac{x_2+x_1}{2}

(4)LR:这种情况要分两类讨论,如果 x_1 距离 0 的距离小于 x_2 距离 m 的位置,则相遇时间为 m-x_2+\frac{x_1+x_2}{2},否则为m+\frac{x_1-x_2}{2}

由于机器人的速度等于1,那么要求两个机器人在整数点相遇其实等价于要求相遇时间为整数,由上面四种情况可以发现:只有两个机器人所在坐标的奇偶性相同才可能相遇,自然而然地就可以想到将机器人分奇偶进行处理。

奇偶分组后,只要解决其中一组的相遇先后顺序,另外一组也是同理,故下面都是对奇偶性相同的一组机器人进行讨论。我们可以发现,对于一组机器人的方向序列,相邻的”RL”肯定都是最先相遇的,同时在最左边的”LL”肯定也先相遇,那么先处理完整个方向序列最左边的所有”LL”,并且将相邻的”RL”也碰撞掉后,剩下的只可能是”LRRRR…”或者”RRR….”。类似于”LL”,最右边的”RR”肯定也会最先相遇,所有可以从右往左将所有的”RRRR”处理掉,剩下的只可能是”LR”、”L”、 “R”,LR也可以相遇碰撞,剩下的单个就是永远不会碰撞的机器人。

上述的处理可以用一个栈来实现:每次放入一个机器人,与栈顶比较,如果栈顶和放入的机器人刚好可以构成”LL”或者”RL”,则将栈顶弹出,算出两个机器人的相遇时间,否则将机器人放入栈中,最后的情况就是”LRRRR…”或者”RRR….”,每次弹出两个机器人判断方向进行计算即可,相遇时间的公式在最上方已经给出。

另外需要注意的是题目所给的坐标不是有序的,需要先进行排序。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 3e5 + 10;
const int inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
int ans[maxn];
struct node {
    int id, x;
    char dir;
    const bool operator<(const node &t) const { return x < t.x; }
} in[maxn];

int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        stack<node> sta1, sta2;//定义一个奇数栈和偶数栈
        for (int i = 1; i <= n; i++) {
            in[i].id = i;
            scanf("%d", &in[i].x);
        }

        for (int i = 1; i <= n; i++) {
            getchar();
            scanf("%c", &in[i].dir);
        }
        sort(in + 1, in + 1 + n);//坐标排序
        for (int i = 1; i <= n; i++) {
            if (in[i].x & 1) {//当前机器人的坐标为奇数,压入奇数栈
                if (sta1.empty())//如果栈为空则直接压入即可
                    sta1.push(in[i]);
                else if (sta1.top().dir == 'L') {
                    if (in[i].dir == 'L') {//LL
                        ans[in[i].id] = ans[sta1.top().id] =
                            (sta1.top().x + in[i].x) / 2;
                        sta1.pop();
                    } else {//LR
                        sta1.push(in[i]);
                    }
                } else {
                    if (in[i].dir == 'L') {//RL
                        ans[in[i].id] = ans[sta1.top().id] =
                            (in[i].x - sta1.top().x) / 2;
                        sta1.pop();
                    } else {//RR
                        sta1.push(in[i]);
                    }
                }
            } else {//偶数栈
                if (sta2.empty())
                    sta2.push(in[i]);
                else if (sta2.top().dir == 'L') {
                    if (in[i].dir == 'L') {
                        ans[in[i].id] = ans[sta2.top().id] =
                            (sta2.top().x + in[i].x) / 2;
                        sta2.pop();
                    } else {
                        sta2.push(in[i]);
                    }
                } else {
                    if (in[i].dir == 'L') {
                        ans[in[i].id] = ans[sta2.top().id] =
                            (in[i].x - sta2.top().x) / 2;
                        sta2.pop();
                    } else {
                        sta2.push(in[i]);
                    }
                }
            }
        }
        //最后从右往左处理RR和LR的情况
        while (sta1.size()) {
            node xx = sta1.top();
            sta1.pop();
            if (sta1.empty()) {
                ans[xx.id] = -1;
                break;
            }
            node yy = sta1.top();
            sta1.pop();
            if (xx.dir == yy.dir)//RR
                ans[xx.id] = ans[yy.id] = m - (xx.x + yy.x) / 2;
            else {//LR
                if (yy.x > m - xx.x) {
                    ans[xx.id] = ans[yy.id] = m + (yy.x - xx.x)/2;
                } else {
                    ans[xx.id] = ans[yy.id] = m-xx.x + (xx.x + yy.x) / 2;
                }
            }
        }
        while (sta2.size()) {
            node xx = sta2.top();
            sta2.pop();
            if (sta2.empty()) {
                ans[xx.id] = -1;
                break;
            }
            node yy = sta2.top();
            sta2.pop();
            if (xx.dir == yy.dir)
                ans[xx.id] = ans[yy.id] = m - (xx.x + yy.x) / 2;
            else {
                if (yy.x > m - xx.x) {
                    ans[xx.id] = ans[yy.id] = m + (yy.x - xx.x) / 2;
                } else {
                    ans[xx.id] = ans[yy.id] = m - xx.x + (xx.x + yy.x) / 2;
                }
            }
        }
        //puts("---------------");
        for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
        puts("");
    }
    return 0;
}

D. Armchairs(DP)

题意

有n个座位,用1-n编号,用一个01序列表示,1表示初始有人坐着,0表示空座位。你有一个操作,可以让任意一个人去任意一个空座位,所需要消耗的时间为abs(i-j),其中i表示这个人的座位编号,j表示他要去的座位编号。问你用最少的时间,使得初始时做了人的座椅全空,题目保证人的数量少于等于座椅数量的一半

分析

首先将0和1分别放在两个容器里,用 dp[i][j] 表示已经处理了前 i 个1,且第 i 个1被分配到了第 j 个0的位置的最少花费。我们可以从第i-1个1的情况推出第i个1的情况:由于第i个1被分配到了第j个0的位置,那么第i-1个1肯定分配在第1到j-1个0的某个位置(稍微思考一下就能得出),于是dp[i][j] = min(dp[i-1][k]) + abs(pos1[i]-pos0[j]),1 \leq k \leq j-1 ,其中pos1表示所有1的座位编号,pos0表示所有0的座位编号。时间复杂度为 O(n^3),可以用前缀和优化,我们发现每次枚举k的时候就是为了找到dp[i-1] [1 to j-1]的最小值,而 j 的值每次+1,故可以用一个变量表示这个最小值,在每次循环的时候更新一下就行,可以省去一个循环,优化到 O(n^2)

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
vector<int> p0,p1;
int dp[5555][5555];
int main(int argc, char const *argv[]) {
    int n;
    cin >> n;
    p0.push_back(0);
    p1.push_back(0);
    for(int i = 1; i <= n; i++){
        int x;
        cin >> x;
        if(x == 0) p0.push_back(i);
        else p1.push_back(i);
    }
    memset(dp,0x3f,sizeof dp);
    for(int i = 0; i <= p0.size(); i++) dp[0][i] = 0;
    for(int i = 1; i <= p1.size(); i++) {
        int mmin = 0x3f3f3f3f;
        for(int j = 1; j <= p0.size(); j++) {
            mmin = min(mmin, dp[i-1][j-1]);
            dp[i][j] = min(dp[i][j], mmin + abs(p1[i]-p0[j]));
        }
    }
    int ans = 0x3f3f3f3f;
    for(int i = 1; i <= p0.size(); i++) ans = min(ans, dp[p1.size()-1][i]);
    cout << ans;
    return 0;
}
原网站

版权声明
本文为[Here_SDUT]所创,转载请带上原文链接,感谢
https://cloud.tencent.com/developer/article/2069188