2023NYIST(计科ACM&TC)第一次招新赛——题解

一:整体评价

        一开始出题时对于整体难度的分布:

        最后过题榜


        感觉打的不是很好,看很多人还是只过了一两题,感觉基础还需要加强,五题及以上的只有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。

代码

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是51单片机控制的12864液晶显示系统编程实现所需的代码: ``` #include <reg51.h> #include <intrins.h> #define LCD_DB P0 sbit LCD_RS = P2^6; // RS信号 sbit LCD_RW = P2^5; // RW信号 sbit LCD_E = P2^7; // E信号 sbit LCD_CS1 = P2^0; // CS1信号 sbit LCD_CS2 = P2^1; // CS2信号 void delay(unsigned int i) // 延时函数 { while(i--); } void write_com(unsigned char com) // 写命令函数 { LCD_RS = 0; LCD_RW = 0; LCD_DB = com; LCD_E = 1; _nop_(); _nop_(); LCD_E = 0; } void write_data(unsigned char dat) // 写数据函数 { LCD_RS = 1; LCD_RW = 0; LCD_DB = dat; LCD_E = 1; _nop_(); _nop_(); LCD_E = 0; } void init_lcd() // 初始化函数 { write_com(0xc0); // 设置显示模式 write_com(0x3f); // 允许显示 write_com(0x40); // 设置起始地址 write_com(0xb8); // 设置页地址 write_com(0xc0); // 设置列地址 write_com(0x40); // 设置起始地址 write_com(0xb8); // 设置页地址 write_com(0xc0); // 设置列地址 } void display_string(unsigned char x, unsigned char y, unsigned char *s) // 显示字符串函数 { unsigned char i; if(y == 0) // 第一行居中显示“南阳理工学院” { write_com(0xb8 + x); write_com(0x40); } else if(y == 1) // 第二行居中显示“www.nyist.edu.cn” { write_com(0xb8 + x); write_com(0x48); } else if(y == 2) // 第三行居中显示“电子信息工程专业” { write_com(0xb8 + x); write_com(0x50); } else if(y == 3) // 第四行居中显示尚春芳 { write_com(0xb8 + x); write_com(0x58); } for(i = 0; s[i] != '\0'; i++) { write_data(s[i]); } } void main() { init_lcd(); // 初始化LCD display_string(18, 0, "南阳理工学院"); // 显示第一行 display_string(16, 1, "www.nyist.edu.cn"); // 显示第二行 display_string(16, 2, "电子信息工程专业"); // 显示第三行 display_string(22, 3, "尚春芳"); // 显示第四行 while(1); } ``` 以上代码实现了你提出的要求,第一行居中显示“南阳理工学院”,第二行居中显示“www.nyist.edu.cn”,第三行居中显示“电子信息工程专业”,第四行居中显示尚春芳。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值