E. 羽毛球比赛
【题目描述】
Alice 和 Bob 在打羽毛球。
羽毛球每局的获胜条件如下:
- 若得到至少 21 分,且领先对手至少 2 分,则获胜。
- 若得到 30 分,则获胜。
给定目前的比分 a:b,其中 Alice 得分为 a,Bob 得分为 b。现在,你作为比赛的裁判,请你判断是否有人已经获胜。
【输入格式】
输入一行两个非负整数 a, b (0 ≤ a, b ≤ 30),分别表示 Alice 和 Bob 的得分。保证给定的比分是比赛过程中可能出现的。
【输出格式】
若 Alice 已获胜,输出 Alice;若 Bob 已获胜,输出 Bob;若无人已获胜,输出 Underway。
解题思路:
签到题,分类讨论即可,赛时手速太慢了QVQ。
AC Code:
cpp
void solve()
{
int a, b; cin >> a >> b;
int mx = max(a, b),mi = min(a, b);
if(a >= 21 && a - b >= 2) cout << "Alice" <<endl;
else if(a == 30 && a > b) cout << "Alice" << endl;
else if(b >= 21 && b - a >= 2) cout << "Bob" << endl;
else if(b == 30 && b > a) cout << "Bob" << endl;
else cout << "Underway" << endl;
// cout<<fixed<<setprecision(x)<< ;
}
G. 玻璃碎晶
【题目描述】
一块大小为 nnn 的彩釉玻璃自空中坠落,碎裂成莹润的碎晶,每片碎晶的大小皆为正整数。
绫轻捻这些闪烁的碎晶,于她眼中,一片大小为 xxx 的碎晶是美丽的碎晶,当且仅当 xxx 是大于 1 的奇数。
在所有碎晶都是美丽的碎晶的前提下,绫想知道碎晶数量的最大值。若不存在所有碎晶都是美丽的碎晶的情况,回答 -1 即可。
【输入格式】
本题有多组数据。第一行一个正整数 TTT (1≤T≤1041 \le T \le 10^41≤T≤104),表示数据组数。
对于每组数据:
一行一个正整数 nnn (1≤n≤1091 \le n \le 10^91≤n≤109)。表示彩釉玻璃的大小,即所有碎晶的大小之和。
【输出格式】
对于每组数据:
一行一个整数,表示在所有碎晶都是美丽的碎晶的情况下,碎晶数量的最大值。若不存在所有碎晶都是美丽的碎晶的情况,输出 -1。
解题思路:
这道题是队友写出来的,我还没看完题队友就秒了,手玩几个样例就能发现规律了。
AC Code:
cpp
void solve()
{
int n; cin >> n;
int k = n % 3;
if(n == 1 || n == 2 || n == 4)
{
cout << "-1" << endl;
return ;
}
if(k == 1)
{
cout << n / 3 - 1 << endl;
return ;
}
else
{
cout << n / 3 << endl;
return ;
}
// cout<<fixed<<setprecision(x)<< ;
}
A. 扭蛋
【题目描述】
绫正在商场中闲逛,一台扭蛋机吸引了她的目光。
扭蛋机中共有 nnn 种扭蛋,第 iii 种扭蛋有 aia_iai 个。
- 消耗一个扭蛋币可随机获得一个扭蛋。
- 消耗任意 kkk 个扭蛋可以向商家兑换一个指定币。
- 消耗一个指定币可获得扭蛋机中一个指定种类的扭蛋。
所有扭蛋不会被重新放回扭蛋机。
绫想要集齐 nnn 种扭蛋,即在最后拥有每种扭蛋各至少一个,现在她想要知道,至少需要多少扭蛋币才能保证可以集齐 nnn 种扭蛋。
【输入格式】
本题有多组数据。第一行一个正整数 TTT (1≤T≤30001 \le T \le 30001≤T≤3000),表示数据组数。
对于每组数据:
第一行两个正整数 n,kn,kn,k (1≤n≤3000,1≤k≤3×1051 \le n \le 3000, 1 \le k \le 3 \times 10^51≤n≤3000,1≤k≤3×105),分别表示扭蛋种类数和兑换指定币所需要的扭蛋数量。
第二行 nnn 个正整数,第 iii 个正整数为 aia_iai (1≤ai≤30001 \le a_i \le 30001≤ai≤3000),表示第 iii 种扭蛋的数量。
保证 TTT 组数据中 nnn 的和不超过 300030003000。
【输出格式】
对于每组数据:
输出一行一个整数,表示保证集齐 nnn 种扭蛋至少需要的扭蛋币数量。
解题思路:
比较绕的模拟题,需要维护的变量有点多,大致思路就是从大到小排序,考虑最坏的情况也就是每次都抽到数量最多的扭蛋,然后我们需要用变量维护当前有多少个扭蛋可以用于转为指定扭蛋,还需要有变量来维护当前还需要多少个扭蛋,对于每一组扭蛋我们可以考虑先将这组全部拿完,然后我们判断是否满足条件,如果不满足就继续,如果满足就还会有多种情况,第一个是我们在之前的剩余扭蛋已经满足于转化为目前所需的扭蛋数了,还有一种情况是需要用到此组的一些扭蛋来转化为指定扭蛋,那我们只需要计算出需要多少即可。
AC Code:
cpp
void solve()
{
int n, k; cin >> n >> k;
vector<int> a(n + 1);
for(int i=1;i<=n;i++) cin >> a[i];
int ans = 0LL, sy = 0LL;
sort(a.begin() + 1, a.end(), greater<int> ());
int need = n; // 目前所需的扭蛋数
for(int i=1;i<=n;i++)
{
need --, sy += (a[i] - 1);
int t = sy / k;
if(t >= need)
{
int pre = sy - (a[i] - 1);
int num = need * k - pre;
if(num < 0) // 满足条件后的情况1
{
ans = pre + i;
cout << ans << endl;
return ;
}
a[i] = num + 1LL; // 满足条件后的情况2
for(int j=1;j<=i;j++) ans += a[j];
cout << ans << endl;
return ;
}
}
// cout<<fixed<<setprecision(x)<< ;
}
K. 不许偷吃
【题目描述】
在一次训练结束后,小猪与两位队友以及一名教练共四人相约去吃饭。他们选择了避风塘餐厅,并点了许多点心,如虾饺、红米汤、乳鸽等。
他们总共点了 nnn 份菜,第 iii 道菜包含 aia_iai 个点心。为了实现均分,所有点心的总数一定是 4 的倍数。然而,由于上菜速度较慢,且每道菜的点心数不一定都是 4 的倍数,因此点心往往分批上桌。
每当上一道菜后,如果餐桌上的点心总数不少于 4,四人就会各自吃掉一个点心,直到剩下的点心不足 4 个为止。由于上菜缓慢,在新的点心上桌之前,桌上的点心数始终小于 4。
但是,小猪喜欢偷吃!为了不被发现,小猪只会在餐桌上恰好剩下 1 个点心时,迅速将其吃掉。小猪偷吃后,大家会误以为餐厅份量不足,从而投诉餐厅。而你,作为避风塘的经理,虽然无法加快上菜速度,但可以调整每道菜的上菜顺序。
现在,请你判断,是否存在一种上菜顺序,使得小猪没有机会偷吃点心,从而避免顾客投诉餐厅呢?
【输入格式】
本题有多组数据。第一行一个整数 TTT (1≤T≤1041 \le T \le 10^41≤T≤104),表示数据组数。
对于每组数据:
- 第一行一个整数 nnn (1≤n≤1051 \le n \le 10^51≤n≤105) 表示点的菜品数。
- 接下来一行 nnn 个整数 a1,...,ana_1, \dots, a_na1,...,an (1≤ai≤1001 \le a_i \le 1001≤ai≤100)。
保证 ∑i=1nai\sum_{i=1}^n a_i∑i=1nai 是 4 的倍数,保证 TTT 组数据中 nnn 的和不超过 10510^5105。
【输出格式】
对于每组数据:
如果无论用什么顺序小猪都会偷吃,输出 -1。
否则,输出一个排列 p1,...,pnp_1, \dots, p_np1,...,pn,表示上菜的顺序。第 iii 次上第 pip_ipi 道菜。
如果有多种答案,输出任意一种答案即可。
解题思路:
这道题是一个简单的思维 + 模拟题,我认为是比 A 题要简单一点的,但是不知道为什么过的人没有 A 题多,我们很容易想到需要对 444 进行取模然后分组,对于正好是 444 的倍数,我们可以随便分,然后 111 和 333 可以配对,配完之后我们分两种情况,一种是 111 有剩余,一种是 333 有剩余,对于第一种情况我们需要考虑 111 和 222 配对,可以用 2,2,12,2,12,2,1 为一组,对于第二种情况我们需要考虑 333 和 222 配对,可以用 3,3,23,3,23,3,2 为一组,对于第一种情况如果还有 111 剩余就输出 −1-1−1 , 第二种情况如果还有 333 剩余也是 −1-1−1 (手动模拟一下即可,赛时没想那么多看到数据范围支持模拟就直接模拟了),最后我们需要对剩余的 222 进行分配,这种情况也是一定可以分完,随意分即可。
AC Code:
cpp
void solve()
{
int n; cin >> n; vector<pii> a(n + 1);
vector<pii> y0, y1, y2, y3;
for(int i=1;i<=n;i++)
{
cin >> a[i].fi; a[i].se = i;
if(a[i].fi % 4 == 0) y0.push_back(a[i]);
else if(a[i].fi % 4 == 1) y1.push_back(a[i]);
else if(a[i].fi % 4 == 2) y2.push_back(a[i]);
else if(a[i].fi % 4 == 3) y3.push_back(a[i]);
}
vector<int> ans;
for(auto v : y0) ans.push_back(v.se);
int len = min(y1.size(), y3.size());
for(int i=0;i<len;i++)
{
ans.push_back(y3.back().se); y3.pop_back();
ans.push_back(y1.back().se); y1.pop_back();
}
if(y1.size())
{
len = min(y1.size() / 2, y2.size());
for(int i=0;i<len;i++)
{
ans.push_back(y2.back().se); y2.pop_back();
ans.push_back(y1.back().se); y1.pop_back();
ans.push_back(y1.back().se); y1.pop_back();
}
if(y1.size())
{
cout << "-1" << endl;
return ;
}
if(y2.size())
{
while(y2.size())
{
ans.push_back(y2.back().se); y2.pop_back();
}
}
}
else if(y3.size())
{
len = min(y3.size() / 2, y2.size());
for(int i=0;i<len;i++)
{
ans.push_back(y3.back().se); y3.pop_back();
ans.push_back(y3.back().se); y3.pop_back();
ans.push_back(y2.back().se); y2.pop_back();
}
if(y3.size())
{
int co = 0LL;
while(y3.size())
{
co += y3.back().fi;
if(co % 4 == 1)
{
cout << "-1" << endl;
return ;
}
ans.push_back(y3.back().se);
y3.pop_back();
}
}
if(y2.size())
{
while(y2.size())
{
ans.push_back(y2.back().se); y2.pop_back();
}
}
}
while(y2.size())
{
ans.push_back(y2.back().se); y2.pop_back();
}
for(auto i : ans) cout << i << " ";
cout << endl;
// cout<<fixed<<setprecision(x)<< ;
}
H. 珍珠链
【题目描述】
绫的案头有一串长度为 nnn 的珍珠链 aaa,每颗珍珠有其光彩值,从头至尾第 iii 颗珍珠的光彩值为 aia_iai。
绫手中悬着一串珍珠链 bbb,初始为空。她对这个珍珠链进行若干次操作,第 iii 次操作可从以下两种操作中选择其中一种:
- 将一颗光彩值为 iii 的珍珠串入 bbb 的末尾。
- 将 bbb 中任意一颗珍珠的光彩值提高 1。
绫想要知道:至少需要多少次操作,才能使得珍珠链 bbb 与 aaa 完全相同?若无法使得珍珠链 bbb 与 aaa 完全相同,回答 -1 即可。
【输入格式】
本题有多组数据。第一行一个正整数 TTT (1≤T≤1041 \le T \le 10^41≤T≤104),表示数据组数。
对于每组数据:
- 第一行一个正整数 nnn (1≤n≤5×1051 \le n \le 5 \times 10^51≤n≤5×105)。表示珍珠链 aaa 的长度。
- 第二行 nnn 个正整数,第 iii 个正整数为 aia_iai (1≤ai≤10121 \le a_i \le 10^{12}1≤ai≤1012),表示 aaa 中从头至尾第 iii 颗珍珠的光彩值。
保证 TTT 组数据中 nnn 的和不超过 5×1055 \times 10^55×105。
【输出格式】
对于每组数据:
输出一行一个整数,表示最少操作次数,若无法使得珍珠链 bbb 与 aaa 完全相同,输出 -1。
解题思路:
赛时这道题没有写出来,遗憾打铁,以为是DP,没有状态转移的思路,赛后才知道原来只是一个思维贪心 + 模拟题,我们很容易想到尽量使用升级操作的贪心策略,,所以我们需要求出每一个位置的元素所允许的最大等待次数,然后又因为等待次数一定是非递减的,所以还需要求一遍后缀最小值维护,我们已经有了贪心的策略就不妨先进行n次尾接操作,我们需要从头遍历,用一个变量来维护当前剩余的可以升级操作的次数,还需要一个变量维护从开始到现在一共拖后了多少步,还需要有一个数组来存放每一个位置是在第几个操作完成的(该位置操作后的状态),我们在允许进行跳步时尽量进行跳步,遍历过程中维护好这几个变量即可。
AC Code:
cpp
void solve()
{
int n; cin >> n; vector<int> a(n + 1, 0LL);
for(int i=1;i<=n;i++) cin >> a[i];
vector<int> suffix(n + 1), t(n + 1);
suffix[n] = a[n] - n; // 当前位置的元素最多能拖多少次操作
if(suffix[n] < 0)
{
cout << "-1" << endl;
return ;
}
for(int i=n-1;i>0;i--)
{
suffix[i] = a[i] - i;
if(suffix[i] < 0)
{
cout << "-1" << endl;
return ;
}
suffix[i] = min(suffix[i + 1], suffix[i]); // 要保证等待时间非递减
}
int index = 0LL, ans = n, sy = 0LL;
for(int i=1;i<=n;i++)
{
if(suffix[i] > index) // 可以跳 贪心使用升级操作
{
int old = index;
index = min(index + sy, suffix[i]);
sy -= (index - old);
}
// 预处理suffix时是先默认n次拼接操作 当前珍珠最早在第i步拼,但是现在拖后了index步
t[i] = i + index;
// 当前珍珠变为了在第 i + index = t[i] 步拼,那么我们还需要补 a[i] - t[i]次操作
sy += a[i] - t[i];
// ans 和 sy 的改变保持同步,只需要在这里进行一次更新就好 保证所有的sy都是进行操作过的可用升级次数
ans += a[i] - t[i];
}
cout << ans << endl;
// cout<<fixed<<setprecision(x)<< ;
}