武汉工程大学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;
}