武汉工程大学2020GPLT选拔赛(重现赛)

武汉工程大学2020GPLT选拔赛(重现赛)

2024.7.29 12:00————15:00
IOI赛制
过题数208/400
补题数355/400

  • L1-1 I LOVE WIT
  • L1-2 单位换算
  • L1-3 Pokémon
  • L1-4 颠倒阴阳
  • L1-5 演唱会
  • L1-6 分鸽子
  • L1-7 拼接梯子
  • L1-8 幻想乡炼金学
  • L2-1 特殊的沉重球
  • L2-2 又见火车入栈
  • L2-3 新旷野地带
  • L2-4 缘之空

A - L1-1 I LOVE WIT

题解:
签到题
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

signed main() {
    cout << "I\n"
            "  \n"
            "  L\n"
            "   O\n"
            "    V\n"
            "     E\n"
            "       \n"
            "       W\n"
            "        I\n"
            "         T";
    return 0;
}

B - https://ac.nowcoder.com/acm/contest/87825/B

题解:
签到题
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int n;

signed main() {
    cin >> n;
    double ans = n*120*2.54;
    int res = ans;
    if(res == ans) {
        cout << res;
    }else
    printf("%0.1f",ans);
    return 0;
}

C - L1-3 Pokémon

题解:
给出七个百分数,代表孵化出七只L1-3 Pokémon分别的概率,再给出c,f,表示想要得到第c只,f为1代表想要闪光的L1-3 Pokémon概率为0.01,为0则是想要不闪光的L1-3 Pokémon。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
double a[7];
int c,f;

signed main() {
    for (int i = 0; i <= 6; i++) {
        string s;
        cin >> s;
        int t = 0;
        for (int i = 0; i < s.length()-1; i++) {
            if(s[i] == '.')continue;
            t=t*10+(s[i]-'0');
        }
        a[i] = t;
    }
    cin >> c >> f;
    double ans = 1;
    if(f == 1) {
        ans = a[c]*0.01/100;
    }
    else {
        ans = a[c]*0.99/100;
    }
    printf("%0.2f",ans);
    cout << '%';
    return 0;
}

D - L1-4 颠倒阴阳

题解:
对于32位无符号整数,从最高位的1开始,到最低位每一位取反,然后高低位翻转。输出结果的二进制表示。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int a[35];
int n;

int qpow(int base,int power) {
    int res = 1;
    while(power) {
        if(power&1)res*=base;
        base*=base;
        power >>= 1;
    }
    return res;
}//快速幂模版

signed main() {
    cin >> n;
    int i = 0;
    while(n) {
        if(n & 1) {
            a[i++] = 0;
 //           cout << i-1 << "das";
        }
        else {
            a[i++] = 1;
//            cout << i-1 << "dar";
        }
        n >>=1;
        //每一位取反
    }
    for (i; i < 32; i++) {
        a[i] = 0;
        //剩下的全部都是0
    }
    int ans = 0;
    for (int j = 0; j < 32; j++) {
        if(a[j] == 1)
        ans += qpow(2,31-j);
        //二进制转十进制
    }
    cout << ans << endl;
    return 0;
}


E - L1-5 演唱会

题解:
听演唱会,给出出发时间,路程需要1h22min33s,计算能否赶上这场在19点到21点间的音乐会。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int hh,mm,ss;
int tm = 0;

signed main(){
    string s;
    cin >> s;
    int ls = 0;
    int t = 1;
    for (int i = 0; i < s.length(); i++) {
        if(s[i] == ':') {
            if(t == 1) hh = ls;
            else if(t == 2)mm = ls;
            else if(t == 2)ss = ls;
            t++;ls = 0;
            continue;
        }
        ls = ls*10+(s[i]-'0');
    }
    ss = ls;
    tm = hh*3600+mm*60+ss+3633+22*60;
    //计算到达时间
    if(tm < 19*3600) {
        cout << "arrive on time";
    }
    else if(tm >= 21*3600) {
        cout << "too late";
    }
    else {
        cout << "arrive late";
    }
    return 0;
}

F - L1-6 分鸽子

题解:
n只鸽子,分给m个小伙伴,每个小伙伴得到的鸽子肉要重量相等,得到的鸽子肉不能来自于多只鸽子。
二分看能否分配。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int n,m;
int a[100005];

bool check(int x) {
    int res = 0;
    for (int i = 1; i <= n; i++) {
        res += a[i]/x;
    }
    return res >= m;
}

signed main() {
    cin >> n >> m;
    int sum = 0;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        sum+=a[i];
    }
    sum/=m;
    int l = 0,r = sum+1;
    while(l < r) {
        int mid = (l+r+1)/2;
        if(check(mid))l = mid;
        else r = mid-1;
    }
    cout << l;
    return 0;
}

G - L1-7 拼接梯子

题解:
有k段梯子的长度分别是2的1次方,2次方,…k次方,求能否刚好拼接成长度为L的梯子,同时输出最长的材料长度。
不难看出当把L转化为二进制时,每一位1都对应相应的梯子,如果第0位有1则无法,或者位数超过k也无法。然后输出最高位的1即可。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
int a[70];

int k,l;

int qpow(int base,int power) {
    int res = 1;
    while(power) {
        if(power&1) res*=base;
        base*=base;
        power>>=1;
    }
    return res;
}

signed main() {
    cin >> k >> l;
    int i = 0;
    while(l) {
        if(l & 1) {
            a[i++] = 1;
        }
        else a[i++] = 0;
        l >>= 1;
    }
    bool st;
    if(a[0] == 1)st = false;
    else if(i-1 <= k)st = true;
    else st = false;
    if(st){cout << "Yes" << endl;
    for (int j = i-1; j >= 0; j--) {
        if(a[j] == 1) {
            cout << qpow(2,j);
            //这个地方很有趣,不能直接1 << j
            //可以看一下j是32的时候答案会是多少哦。
            return 0;
        }
    }}
    else cout << "No" << endl;
    return 0;
}

H - L1-8 幻想乡炼金学

题解:
给出一个炼金式,去除所有空格,对于每个用数字重复的原子把它直接展开,括号不会嵌套。
题目很简单,主要是要注意读题⚠️,每个用数字重复的原子,例如(Po){3}应该展开为(PoPoPo),而不是(PPPooo)。题意理解有误导致这题只拿了八分还浪费了很多时间,但这也是没办法的事。
代码:

#include<bits/stdc++.h>

using namespace std;
string s;
int lm;
string ans;

signed main() {
    getline(cin,s);
    string la ="ABC";
    for (int i = 0; i <s.length(); i++) {
        if(s[i] == ' ')continue;
        if(s[i] == '(') {
            i++;
            while (s[i] != ')' && i < s.length()) {
                if(s[i] == ' ') {
                    i++;   
                    continue;
                }
                la += s[i];
                i++;
            }
        }
        else if(s[i] == '{') {
            int j = i-1;
            i++;
            while(s[i] == ' ')i++;
            if('0' <= s[i] && s[i] <= '9'){
            while (s[i] != '}' && i < s.length()) {
                if(s[i] == '}')break;
                if(s[i] == ' ') {
                    i++;
                    continue;
                }
                lm = lm*10+(s[i]-'0');
                i++;
            }}
  //          cout << "LM" << lm << endl;
            while (s[j] == ' ')j--;
            if(s[j] == ')') {
                string ab[50];
                int ai = 0;
                for (int ii = 3; ii < la.length(); ii++) {
                    if('A' <= la[ii] && la[ii] <= 'Z') ai++;
                    ab[ai] += la[ii];
                }
                for (int ii = 0; ii <= ai; ii++) {
                    for (int jj = 1; jj <= lm; jj++) {
                        ans+=ab[ii];
                    }
                }
                la = "ZDS";
            }
            else {
                bool fl = true;
                string lp;
                while (fl && j >= 0) {
                    if(s[j] == ' ') {
                        j--;
                        continue;
                    }
                    lp = s[j]+lp;
                    if('A' <= s[j] && s[j] <='Z')fl = false;
                    j--;
                }
                for (int i = 1; i <= lm-1; i++) {ans+=lp;
                }
                if(lm == 0) {
                    string res;
                    for (int i = 0; i < ans.length()-lp.length(); i++) {
                        res += ans[i];
                    }
                    ans = res;
                }
 //               cout << "LP" << lp << endl;
            }
        }
        else ans+=s[i];
        lm = 0;
    }
    cout << ans << endl;
    return 0;
}

I -L2-1 特殊的沉重球

题解:
精灵宝可梦!可以把多只宝可梦装进一个沉重球,只要不超过它的限制,先给出宝可梦的数量,沉重球的最大承重,和每只宝可梦的重量。输出最少需要的沉重球。
从最重的开始放,不然会频繁需要增加球,运用dfs爆搜即可。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

int n,w;
int c[30];
int sum[30];
int ans = 1e9;
int res;

void dfs(int a, int b) {
    //第a只动物,第b个沉重球
    if(b >= ans)return ;
    //已经不可能更少的沉重球
    if(a == n+1) {
        ans = min(b,ans);
        return ;
    }
    for (int i = 0; i <= b; i++) {
        if(sum[i] + c[a] <= w) {
            sum[i]+=c[a];
            dfs(a+1,b);
            sum[i]-=c[a];
        }
    }
    sum[b+1] += c[a];
    dfs(a+1,b+1);
    sum[b+1] -= c[a];
    //必须返回sum状态!!!
    return ;
}

signed main() {
    cin >> n >> w;
    for (int i = 1; i <= n; i++)cin >> c[i];
    sort(c+1,c+1+n,greater<int>());
    //从小到大排序会超时
    dfs(0,0);
    cout << ans+1 << endl;
    return 0;
}

J -L2-2 又见火车入栈

题解:
火车的进栈出栈,用in或out记录,记录一定合法。下面给出未排序的q次询问,表示处理完第x条记录后,第y个进入火车站的火车编号是多少。
先用a数组储存火车的进出栈,然后将询问排序,查找第y个进入火车的火车编号,具体见注释。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1e6+10;
int n,q;
int a[N],b[N];
int ans[N];

struct jm {
    int x,y;
    int fg;
};

vector<jm>c;

bool cmp(jm aa,jm bb) {
    return aa.x < bb.x;
}//先处理早的记录后的状况

signed main () {
    cin >> n;
    int p = 0;
    for (int i = 1; i <= n; i++) {
        string s;
        cin >> s;
        if(s == "in") {
            a[i] = 1;
        }
        else a[i] = 0;
    }
    cin >> q;
    for (int i = 1; i <= q; i++) {
        int x,y;
        cin >> x >> y;
        c.push_back({x,y,i});
    }sort(c.begin(),c.end(),cmp);
    
    int res = 1;
    int wz  = 1,dq = 0;
    for (int i = 1; i <= n; i++) {
        if(a[i] == 1) {
            b[wz++] = res;
            res++;
            //进站,位置加一,火车加一
        }
        if(a[i] == 0) {
            b[wz-1] = 0;
            wz--;
            //出站,位置减一,火车变0
        }
        while(i == c[dq].x) {
            ans[c[dq].fg] = b[c[dq].y];
            dq++;
        }//要注意多次寻找同一个记录的火车的情况,必须用while
//         for (int j = 1; j < wz; j++) {
//             cout << b[j] << ' ';
//         }cout << endl;
//         cout << wz << '/' << res << '/' << i << endl;
    }
    for (int i = 1; i <= q; i++) {
        cout << ans[i] << "\n";
        //!!!用endl会超时,看来时间是真的差很多啊
    }
    return 0;
}

L - L2-4 缘之空

题解:
n个人q次询问,如果俩个人是直系血亲或者亲缘等级小于等于4就不能结婚。输出俩个人能否结婚,以及亲缘等级。
给出一个爆搜的tle的代码,拿了15分。
一道最近公共祖先lca算法模版题。具体见注释。
代码:

//一串tle的代码,非常之暴力谢谢

#include<bits/stdc++.h>

using namespace std;
#define int long long

int n,q;
vector<int>a[100010];
vector<int>z[100010];
int res;
bool st[100010];
bool aaa,bbb;
int ans;

void dfs(int u,int v) {

//    cout << u << ' ' << v << ' ' << res << endl;
    if(aaa)return ;
    st[u] = true;
    for (auto x : a[u]) {
 //       cout << x << '/' << u << endl;
        if(x == v) {
            ans = res;
            aaa = true;
            return ;
        }
        else if(!st[x]){
            st[x] = true;
            res++;
            dfs(x,v);
            res--;
            st[x] = false;
        }
    }
    return ;
}

void dfss(int u,int v) {

//    cout << u << ' ' << v << ' ' << res << endl;
    if(bbb)return ;
    for (auto x : z[u]) {
 //       cout << x << '/' << u << endl;
        if(x == v) {
            bbb = true;
            return ;
        }
        else{
            res++;
            dfss(x,v);
            res--;
        }
    }
    return ;
}

signed main() {
    cin >> n >> q;
    for (int i = 1; i < n; i++) {
        int f,c;
        cin >> f >> c;
        a[f].push_back(c);
        a[c].push_back(f);
        z[f].push_back(c);
    }
    for (int i = 1; i <= q; i++) {
        int u,v;
        cin >> u >> v;
        res = 1;
        memset(st,0,sizeof st);
        aaa = false;
        bbb = false;
        dfs(u,v);
        dfss(u,v);
        dfss(v,u);
        if(aaa && ans > 4&& !bbb)cout << "YES" << endl << ans << endl;
        else cout << "NO" << endl << ans << endl;
    }
    return 0;
}
#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 100010;
vector<int>a[N];
int n,q,root;
int du[N],dep[N],fa[N][20];
//第i个节点向上跳2的j次方的祖先节点

void dfs(int x,int father) {
    dep[x] = dep[father]+1;
    //父节点的深度加一
    fa[x][0] = father;
    //最近的父节点
    for (int i = 1; i <= 19; i++) {
        fa[x][i] = fa[fa[x][i-1]][i-1];
        //这个地方很奇怪,它是倍增的
        //比如fa[x][3] = fa[fa[x][2][2];
        //x向上2的点再向上2是3的位置
    }
    for (auto m : a[x]) {
        if(m!= father)dfs(m,x);
        //开始往下遍历,只要不是父亲就遍历
    }
}

int lca(int u,int v) {
    if(dep[u] < dep[v]) {
        swap(u,v);
        //让节点u去跳
    }
    for (int i = 19; i >= 0; i--) {
        if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];
        //只要u的父亲大于等于v,就一直向上跳到父节点
    }
    if(u == v)return v;
    //v是u的父节点的情况
    for (int i = 19; i >= 0; i--) {
        if(fa[u][i] != fa[v][i]) {
        //一直到俩个人最远的父节点不一样的时候
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
    //找到最近的那个一样的父节点
}

signed main() {
    cin >> n >> q;
    for (int i = 1; i < n; i++) {
        int f,c;
        cin >> f >> c;
        a[f].push_back(c);
        a[c].push_back(f);
        du[c]++;
    }
    for (int i = 1; i <= n; i++) {
        if(du[i] == 0) {
            root = i;
            //入度为0的点就是根节点
            break;
        }
    }
    dfs(root,0);
    while(q--) {
        int t,d;
        cin >> t >> d;
        int ans = dep[t]+dep[d]-2*dep[lca(t,d)];
        //俩个点的深度减去最近公共祖先的深度的倆倍就是俩者的距离
        if(ans <= 4 || t == lca(t,d) || d == lca(t,d)) {
        //如果一个人是祖先或者亲缘等级小于等于四,都不可以
            cout << "NO" << endl << ans << endl;
        }
        else cout << "YES" << endl << ans << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值