SMU Summer 2024 Contest Round 1
2024.7.8 9:00————11:00
过题数0/6
补题数5/6
- AtCoder-abc126_c
- AtCoder-abc128_d
- AtCoder-abc134_e
- AtCoder-abc127_e
- AtCoder-abc131_e
- AtCoder-abc127_d
A - Dice and Coin
读错题了以为每次都要抛掷骰子和硬币,加上不熟悉log和pow函数所以没解出来,其实应该是不难的。
题解:
有一个n面骰子,给出数字k,当结果大于等于k或等于0时游戏结束。首先抛掷骰子作为结果,然后反复抛硬币,正面结果数翻倍,反面清零。求有多大的概率赢下这场比赛,保留十二位小数。
分俩种情况考虑,抛掷数直接大于等于k,以及第一次并未大于等于k,后抛硬币的失败几率是2的n次方乘以它本身,用到log和pow函数,函数不熟悉以及注意小数单位即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
double n,k;
cin >> n >> k;
double ans = 0;
for (int i = 1; i <= n; i++) {
if (i >= k) {
ans += (double)(n-i+1)/n;
//注意加double
break;
}
else {
int ls = log2(k/i);
if (i*pow(2,ls) != k) {
ls++;
}
//不相等时得多抛一次
ans += 1.0/((double)pow(2,ls))/(double)n;
}
}
printf("%0.12lf\n",ans);
return 0;
}
B - equeue
题解:
一个双向队列,可以进行k次操作,每次操作可以在左右侧拿出或放入一个东西,必须得在拿的位置有宝石时才可进行此操作。
数据较小,可以暴力解决,遍历左右拿几个,剩余的操作次数用来放回最小的几个负数字。具体见注释。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int v[600];
signed main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
int ans = 0;
for (int l = 0; l <= n; l++) {
for (int r = 0; r <= n-l; r++) {
//最多也就拿空了吧
int sum = 0;
if(l+r>k)break;
//最多进行k次操作
int st[600];
memset(st,0,sizeof st);
int tot = 0;
for (int i = 1; i <= l; i++) {
st[tot++] = v[i];
sum+=v[i];
}//本来想用优先队列的,但还是得在里面排序其实是一样的
for (int i = n; i >= n-r+1; i--){
st[tot++] = v[i];
sum+=v[i];
}
sort(st,st+tot);
//小的值放回去
for (int i = 0; i < k-l-r; i++) {
if(st[i] >= 0)break;
//大的都得留下
sum-=st[i];
// cout << sum << '.';
}
// cout << l << ' ' << r << ' ' << sum << endl;
ans = max(sum,ans);
//寻找最大值
}
}
cout << ans;
return 0;
}
C - Sequence Decomposing
题解:
给出n个数字组成数组a,别的花里胡哨的涂颜色不管,就是求序列中最多有多少个递增子序列。
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
long long a[n];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
multiset<long long>s;
s.insert(a[0]);
for (int i = 1; i < n; i++) {
auto x = s.lower_bound(a[i]);
if (x == s.begin()){
// cout << i << ' ';
s.insert(a[i]);
}
else {
x--;
s.erase(x);
s.insert(a[i]);
}
}
cout << s.size() << endl;
return 0;
}
E - Friendships
注意一个地方,不要遇到树就走,很多是思维问题,其实可以尝试的,联通块之类的同理,也会以dfs居多。
题解:
n个节点,要求有k组i,j节点满足最小路径是2,输出一个满足条件的图。
可以想到所有节点跟1个节点相连时,可以得到最大k是(i-1)*(i-2)/2,每俩个节点之间连上一条线,就会少一种情况,就可以得出代码。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
signed main() {
cin >> n >> k;
if(k > (n-1)*(n-2)/2)cout << -1 << endl;
//最多的线都不够你的要求
else {int m = n-1+(n-1)*(n-2)/2-k;
cout << m << endl;
for (int i = 2; i <= n; i++) {
cout << 1 << ' ' << i << endl;
}
int res = 0;
bool st = true;
if(k*2 == (n-1)*(n-2))return 0;
//这里单判了一下,不然底下会先输出再停止
for (int i = 2; i <= n; i++) {
for (int j = i+1; j <= n; j++) {
cout << i << ' ' << j << endl;
res++;
if(res == (n-1)*(n-2)/2-k){
//这次之后就足够,其实可以直接return 0
st = false;
break;
}
}
if(!st)break;
}
}
return 0;
}
F - Integer Cards
第一道就做的这个,用了multiset,tle了,优先队列不太熟悉,加上时间不太够,没做出来。
题解:
给定n张卡片,m轮操作,每次给出b张大小为c的卡片,求替换后的最大值。
直接暴力求解会tle,必须找出有几个c,可以替换多少个,然后在相应位置替换。
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
long long n,m;
cin >> n >> m;
multiset<long long>a;
long long ln = n;
for (int i = 0; i < n; i++) {
long long x;
cin >> x;
a.insert(x);
}
vector<pair<int,int>>bc;
map<int,int>mp;
while (m--) {
long long b,c;
cin >> b >> c;
mp[c]+=b;
}
for (auto &[c,b] : mp) {
bc.push_back({c,b});
}
for (int i = bc.size(); i >= 0; i--) {
auto [c, b] = bc[i];
while (c > *a.begin() && b>0) {
b--;
a.erase(a.begin());
a.insert(c);
}
}
long long ans = 0;
for (auto x : a) {
ans+=x;
}
cout << ans << endl;
return 0;
}