一:整体评价
一开始出题时对于整体难度的分布:
最后过题榜
感觉打的不是很好,看很多人还是只过了一两题,感觉基础还需要加强,五题及以上的只有11个人,七题及以上只有两个。而且前后差距有点大。
赛后我觉得可以一般都可以补到七道左右,都不是很难,然后前面的同学可以8-9道题。前三最好补到9道把,然后就是基础比较弱的五道感觉还是没有问题的。
最后加油补题把,补题对一场比赛很重要,继续加油。
二:题解
A 喝一杯吗
思路
这题应该比较难,但是又比较简单,因为鱼越大鱼越小…
分析题意,也就是选取x天,然后利用优惠券使价格最低,分析一下思路就出回来了,在每一张优惠券过期前,将它使用在价格最低的那天上,因为答案天数是递增的的,类似于前缀和,所以大可以把所有优惠券放在一天上,但是由于有过期这个限制,所以把它用在过期前价格最低的那天;
那么第一步我们要做的首先是对优惠券进行排序,因为他没有确保日期是递增的,但是一张优惠券存储了两个值:优惠的钱数和有效期,所以不难想到开一个结构体存储;
struct aaa
{
int day,money;
}b[N];
bool cmp(aaa x,aaa y)
{
if(x.day==y.day)
{
return x.money>y.money;//哪个在前面都无所谓
}
return x.day<y.day;
}
排序之后就该使用优惠券了,要记得优惠券边使用边更新那天的价格,
这个的复杂度是O(n)的,相当于n天被分成了m段;
全部更新完后,优惠券就全部使用完了,于是我们对价格进行排序然后计算前缀和就可以得到答案了:
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
typedef pair<int,int>PII;
int a[N];
struct aaa
{
int day,money;
}b[N];
bool cmp(aaa x,aaa y)
{
if(x.day==y.day)
{
return x.money>y.money;//哪个在前面都无所谓
}
return x.day<y.day;
}
signed main()
{
// std::ios::sync_with_stdio(false);
// std::cin.tie(nullptr);
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
// cin>>a[i];
scanf("%lld",&a[i]);
}
for(int i=1;i<=m;i++)
{
cin>>b[i].day>>b[i].money;
}
sort(b+1,b+1+m,cmp);
int mmin=a[1];//记录1到x天的最小值
int now=1,pos=1;
//now是这张优惠券从哪天开始遍历(因为1到now天的最小值已经被mmin记录了),也是上一张优惠券的结束
//pos相当于一个标记,标记要更新的价格是哪一天的,也就是最小值在哪一天
for(int i=1;i<=m;i++)
{
for(int j=now;j<=b[i].day;j++)
{
if(a[j]<mmin)
{
mmin=a[j];
pos=j;
}
}
a[pos]-=b[i].money;
mmin=a[pos];
now=b[i].day;
}
sort(a+1,a+1+n);
int sum=0;
for(int i=1;i<=n;i++)
{
sum+=a[i];
// cout<<sum<<" ";
printf("%lld ",sum);
}
cout<<endl;
}
return 0;
}
B 重生之我回到了2023年的那次高考
思路
这题应该没有啥思路吧。某出题人说:额,应该不会有人wa了4次才过吧,应该不会吧。
代码
#include<stdio.h>
int main(){
printf(“A”);
}
C 来来来,和我一起大喊A!B!C!
思路
本题作为防ak的题,含金量和思维量还是很不错的。
我们需要把将两个字符串按照Y中C字母来分成一段一段的,然后分来来计算。
如果Y中某位置字母是C那么X的对应字母也必须是C,否则不成立。
同时,对于每一段而言,要考虑到X中只能把AB替换成BA,而不能把BA替换成AB,所以我们需要从左向右遍历的途中,将每一段X的中A与C的数量记录下来,看是否能与Y中的A去对应匹配(优先用X的A去匹配Y的A,如果X中A的数量不够,再用C去匹配Y中的A)。假如这一段结束了,但X中的A依旧有剩余,或者在这一段中途出现了无法匹配的情况,就是不成立。假如每一段都能匹配,则该样例成立。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PII;
const int N=998244353;
int n,m;
void icealsoheat(){
cin>>n;
string a,b;
cin>>a>>b;
for(int i=0;i<n;i++){
if(b[i]=='C'&&a[i]!='C'){
puts("No");
return;
}
}
int an,sn;
an=sn=0;
for(int i=0;i<n;i++){
if(b[i]=='C'){
if(an>0){
puts("No");
return;
}
sn=an=0;
}
else{
if(a[i]=='C')sn++;
else if(a[i]=='A')an++;
if(b[i]=='A'){
if(sn==0&&an==0){
puts("No");
return;
}
else if(an>0)an--;
else sn--;
}
}
}
if(an>0){
puts("No");
return;
}
puts("Yes");
}
signed main(){
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
int _;
_=1;
cin>>_;
while(_--){
icealsoheat();
}
}
D 暖色记忆
思路
我们既然想要保留的数最大,那么我们肯定是要删除前n/2小的数保留后面较大的数,然后依次递增的往上选择,这样对应的除以2的操作就是,最大的数除以2,第二大的数除以22 ………这道题的思路是很简单,不过就是有一个坑点,如果你是使用的一个变量来表示这个除数,就是你不断进行乘2的操作的话,它很快就会爆 long long!!
代码
E yu儿要远航
思路
仔细思考这题维度其实没有啥用,所以只要看经度就可以了。
经度的话有[-180,180),每次对于给出的两个点我们都可以找到一条路径,然后将这个路径上的点都标记为走过,仔细想这里会有一个问题,标记的时候数组下标没有负数,所以我们可以将经度都+180,这样相对的大小就没有变,然后最后输出的时候在减去180即可。
但是这样又会出现一个问题,会有一种样例只有不到1的经度没走过,比如这个样例
6
0 0
0 -90
0 -180
0 -91
0 1
0 179
对于这个样例要输出179.5。但是我们标记并没有179.5,所以我们可以将经度在*2.这样就不会出现0.5的情况。然后再进行标记即可,最后输出的时候判断是否有0.5即可。
还有一个小点就是如果前后两个经度差180,那直接输出yes就行,因为这样绝对可以环球。
代码
#include<bits/stdc++.h>
int f[1000], a[1005];
void solve() {
int n;
scanf("%d", & n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d%d", & x, & a[i]);
a[i] += 180;
a[i] *= 2;
}
n++;
a[n] = a[1];
for (int i = 1; i < n; i++) {
int x = a[i], y = a[i + 1];
if (x > y) {
int tmp = x;
x = y;
y = tmp;
}
if (y - x == 360) {
printf("yes\n");
return;
}
if (y - x < 360) {
for (int i = x; i <= y; i++) f[i] = 1;
} else {
for (int i = 0; i <= x; i++) f[i] = 1;
for (int i = y; i <= 720; i++) f[i] = 1;
}
}
for (int i = 0; i <= 720; i++) {
if (!f[i]) {
printf("no ");
double ans = (double) i / 2.0 - 180.0;
printf("%.1lf", ans);
return;
}
}
printf("yes\n");
}
signed main() {
solve();
return 0;
}
F 关于某冰被ch与杨老板压榨而不得不出一个签到这件事儿
思路
这题是个签到题,考察了各位的数学小小思维的能力。我们如何选择才能是答案最小,通过基本不等式,我们知道,我们需要把大的值尽可能的往单独的盘子里装。而遇到只能装在同一个盘子里的两个值,我们尽可能的让这两个值的查最大,这样才能使答案尽可能的最小。
部分代码
long long n,m;
long long b[500005];
void icealsoheat(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
sort(b+1,b+1+n);
long long ans=0;
long long id=1;
long long op=n-m;
for(int i=1;i<=op;i++){
ans+=(b[i]+b[2*op-i+1])*(b[i]+b[2*op-i+1]);
}
for(int i=2*op+1;i<=n;i++){
ans+=b[i]*b[i];
}
printf("%lld\n",ans);
}
G 假签还是真签!
思路
因为点(x,y)只能向↗或←走,所以x无法到达它下面的点。然后向↗移动点(x,y)直到与目标点在一条x轴上时,判断目标点在点(x,y)左面还是右面即可。
代码
H wkw不要写这题
思路:
就按照题意判断就行,每次反转完都判断是否是完美矩阵,一共最多反转四次,因为反转操作每次都要用到,所以可以写一个函数进行翻转。
代码
#include<stdio.h>
int a,b,c,d;
void change(){
int tmp=a;
a=c;
c=d;
d=b;
b=tmp;
return;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int f=0;
scanf("%d%d%d%d",&a,&b,&c,&d);
for(int i=0;i<4;i++){
if(a<b&&c<d&&a<c&&b<d){
f=1;break;
}
else {
change();
}
}
if(f==1) printf("YES\n");
else printf("NO\n");
}
}
I 买饼干的小坤
思路
思路很简单就是模拟题目上意思进行一个循环操作就行,不过要注意的是m==1的时候就可以直接计算出最终的结果跳出循环,否者会超时!!!
代码
J 立方和?
思路
我们可以先for循环确定a,再用二分查找b。