CCSUTrainingRound 2(C++)部分题解

题目:人人有钱拿(易)

链接:https://ac.nowcoder.com/acm/contest/53254/A

题目描述:

PhieAsh 常常有一些不切实际的幻想。今天他在洗头时便想到:“如果全世界每个人给我一分钱,我不就是一个大富翁了吗?”PhieAsh 主张人人平等,他希望每个人都能当上大富翁。于是他在梦中安排:让所有人排成一列,按队伍的顺序(从前向后)每个人都从其他所有人拿一分钱。在这个过程前,每个人都至少有 0.01×(n−1)元钱。现在请你编程,帮助 PhieAsh 算出所有人最后的资产。

输入描述:

 输出描述:

输入输出:

想法:如我dag所说这个题目就是“收支平衡,所以直接输出就完事””!很简单的,多种表示方法:

①运用STL来写

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T;
    cin >> T;
    while (T--) 
    {
        int n;
        cin >> n;
        std::vector<int> s(n);
        for (auto &i : s)
        {
            cin>>i;
        }
        for (auto &i : s)
        {
            cout << i << " ";
        }
        cout <<endl;
    }
    return 0;
}

②正常直接输入输出方法

 #include<bits/stdc++.h>
 using namespace std;
 #define int long long
 int t,a[200005];
  signed main()
  {
  	cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            int x;
            cin>>x;
            cout<<x<<' ';
        }
        cout<<endl;
    }
  	return 0;
  }

题目: 一剑统治怜悯,一剑送葬绝望

链接:https://ac.nowcoder.com/acm/contest/53254/C?&headNav=acm

题目描述:

xiaoxiao 是一个农批,他最喜欢玩的英雄就是干将莫邪,这英雄有两个技能都是按照一定飞行轨迹扔出一对剑,如图所示:

 现在只考虑使用某一个技能(某一对剑)的前提下,为使伤害最大化,xiaoxiao 需要通过走位使得两剑交汇处恰好命中敌方。但现在 xiaoxiao 已经 17 连败被打破防了,他不知道该如何走位,所以他把手机交给你了!

xiaoxiao 操作的干将莫邪现在位于(sx,sy)点,面对在点(tx,ty)挂机的敌方(即地方不能移动)时,xiaoxiao首先会朝着某一个方向移动某距离,随后出剑使得两剑交汇处恰好命中敌方。下图中已经可以出剑命中敌方。

 

 请你回答,xiaoxiao 首先该向哪个方向移动多少距离?

输入描述:

 输出描述:

输入输出:

 

想法:总结方法就是解一个数学题目“ 一开始就有一个坐标轴,那么使用技能的点,可以保持和敌方的y一致,x的坐标相差2*√c/a,然后分别输出 使用技能的点与 原坐标的 横纵坐标差就行了,主要想法就是!’C 移动到(tx,ty)为圆心,sqrt(4c/a)为半径的圆上就行'!

注意:此题不唯一,有很多种!!

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    double sx,sy,tx,ty,m,n;
    cin>>sx>>sy>>tx>>ty>>m>>n;
    tx -= 2*sqrt(n/m);
    sx=tx-sx,sy=ty-sy;
    printf("%.8lf %.8lf",sx,sy);
    return 0;
}


 

题目:字符串子序列

链接:https://ac.nowcoder.com/acm/contest/53254/E

题目描述:

给定字符串 s 和 p ,判断 p 是否是 s 的子序列。如果是则输出 "YES",如果不是则输出 "NO"。
对于英文字符,不区分大小写,也就是说对于字符 "A" 和字符 "a" ,我们认为它们是相同的字符。

(∗) 这里的子序列,指的是从一个字符串中不重复地选取一些字符,按照原来的先后顺序组成一个新字符串,这个新字符串就称为原字符串的一个子序列。
例如字符串 "ac" 是字符串 "abc" 的子序列,而 "ca" 不是。

输入描述: 

输出描述: 

 输入输出:

 想法:①因为题目描述对于大小写字母是不分的,因此我们就有一个将字母统一的步骤(要么全部小写,要么全部大写),在c++STL中提供了这样一种方法来转换字符串的大小写问题:

C++中有两个函数可进行快速变换大小写,tolower()函数是把字符串都转化为小写字母;touppre()函数是把字符串都转化为大写字s字符串中的字符串转换为大写字母可写为:

                      transform(s.begin(),s.end(),s.begin(),::tolower);

         ②第二步就是去找它的子序列了,利用两个数组遍历查找就好,只要根据它的长度就能判断出是否为它的子序列;

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,i,j=0;
    cin>>n;
    string s;
    cin>>s;
    int m;
    cin>>m;
    string p;
    cin>>p;
    transform(s.begin(), s.end(), s.begin(), ::tolower);//全部转换成小写字母
    transform(p.begin(), p.end(), p.begin(), ::tolower);
    for(i=0;i<n;i++)//遍历数组
    {
        if(s[i]==p[j])//判断是否有相同的字符
        {
            j++;//用来计数,记载相同的时候,所含p的长度
        }
    }
    if(j==m)//判断是否相等,相等就是子序列,反之则反
    {
        cout<<"YES";
    }
    else
    {
        cout<<"NO";
    }
    return 0;
}

漂亮学姐说她有更加简答的办法,因为transform那个太长了,她记不住,因此她就只用了tolower这样的函数,下面是她的代码:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
void solve()
{
    string a,b;
    cin>>n>>a>>m>>b;
    ll j=0;
    for(int i=0;i<a.size();i++)
    {
        if(tolower(a[i])==tolower(b[j]))j++;
        if(j==m)break;
    }
    if(j==m)puts("YES");
    else puts("NO");
}
signed main()
{
    //TT
    solve();
    return 0;
}

题目: 数字全排列

链接:https://ac.nowcoder.com/acm/contest/53254/F

题目描述:

使用0,1,2,3,4,5,6,7,8,9 共十个数字任意排列组成一个十位数。现在要求你用程序求出满足下列条件的十位数的个数:
1.数字 0 不能排在最高位。
2.所有数字不能重复出现。
3.该十位数是 n 的整数倍

输入描述:

 输出描述:

 输入输出:

 想法:这个题目数据规模其实并不是很大,STL中提供了一种暴力写法用std::next_permutation就行。具体介绍next_permutation,就不介绍了,我贴了一个博主的链接,大家可以看看,或者去哔站学一下,就好哒

std::next_permutation链接:https://blog.csdn.net/weixin_45676319/article/details/110314904?ops_request_misc=&request_id=&biz_id=102&utm_term=std::next_permutation&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-110314904.142^v73^insert_down4,201^v4^add_ask,239^v2^insert_chatgpt&spm=1018.2226.3001.4187

下面就是用STL实现的代码了:

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n;
    cin>> n;
    long long ans=0,sum;
    std::vector<int> s = {1,0,2,3,4,5,6,7,8,9};
    do {
          sum = 0;
          for (auto i : s) 
           {  
               sum=sum*10+i;
           }
           ans+=sum%n==0;
       } while (next_permutation(s.begin(),s.end()));
    cout << ans;
    return 0;
}

 当然还有第二种办法,就是写数位dp,大家也可以看看吧

对于数位dp我也贴一个介绍吧:https://blog.csdn.net/hzf0701/article/details/116717851?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167887786516800226585370%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167887786516800226585370&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-116717851-null-null.142^v73^insert_down4,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=%E6%95%B0%E4%BD%8Ddp&spm=1018.2226.3001.4187

#include <bits/stdc++.h>
using namespace std;

long long sum = 0, s[11] = {0}, book[11] = {0}, n, n1 = 0;
void dfs(int step)
{
    if(step == 10)
    {
        long long x = 0, x1 = 10;
        if(s[0] != 0)
        {
            for(int i = 0; i < 10; i++)
            {
                x += s[i];
                x *=10;
            }
            x /= 10;
            if(x%n == 0)
                sum++;
        }
    }
    for(int i = 0; i < 10; i++)
    {
        if(book[i] == 0)
        {
            book[i] = 1;
            s[step] = i;
            dfs(step + 1);
            book[i] = 0;
        }
    }
}
int main()
{
    cin >> n;
    dfs(0);
    cout << sum;
    return 0;
}

题目:最大乘积子数组

链接:https://ac.nowcoder.com/acm/contest/53254/I

题目描述:

给定一个长度为 n 的数组,你的任务是找到一个具有最大乘积的非空子数组。

(∗) 这里的子数组,指的是原数组中连续的一段数,比如 [1,2,3] 是数组 [5, 1, 2, 3,0] 的一个子数组,而 [5,2,3] 则不是。

输入描述: 

 输出描述: 

 输入输出:

想法:总的来说就是不断去找那个最大值

由于存在负数,那么会导致最大的变最小的,最小的变最大的。因此还需要维护当前最小值imin

保证数组连着 需要统计当前值的最大值和最小值 方便下一位的计算
三个值取最大 (最小值乘以当前数 当前数 最大值乘以当前数)
三个值取最小 ...

如果实在还不理解的话,可以参考力扣解法:https://leetcode.cn/problems/maximum-product-subarray/solution/cheng-ji-zui-da-zi-shu-zu-tu-jie-dpzui-q-jjzv/

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,i,j;
    int a,b,c;
    cin>>n;
    int s[n];
    for(i=0;i<n;i++)
    {
        cin>>s[i];
    }
    int zmax,zmin;
    zmax=zmin=s[0];
    int m=s[0];
    for(i=1;i<n;i++)
    {
        a=s[i];
        b=a*zmax;
        c=a*zmin;
        zmax=max({a,b,c});
        zmin=min({a,b,c});
        m=max(m,zmax);
    }
    cout<<m;
    return 0;
}

 题目:HelloWorld,但是数码管

链接:J-HelloWorld,但是数码管_CCSUTrainingRound 2 (nowcoder.com)

题目描述:

输入描述: 

∅ 本题无输入。

输出描述:

思想:这个题目其实读懂题目后是很简单的,本质就是看图找图,然后将图转换为二进制数字,最后再将二进制转换为十进制数字。根据题目可知我们要求的是“helloworld”这个的十进制,总共10个字母,但是我们实际要找的只有7个字母“h” “e” “l” “o” “w” “r” “d”。

因此我们对应两个图分别找出就好:

       

      “h"二进制:1110100   ------------>对应十进制:116

      “e"二进制:1111011   ------------>对应十进制:123

      “l"二进制:0000110   ------------>对应十进制:6

      “o"二进制:1011100   ------------>对应十进制:92

      “w"二进制:1101010   ------------>对应十进制:106

      “r"二进制:1010000   ------------>对应十进制:80

      “d"二进制:1011110   ------------>对应十进制:94

最后就是综合直接输出就行了;

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cout<<"116 123 6 6 92 106 92 80 6 94";
	return 0;
}

题目:JZ的巅峰上分计划 

链接:https://ac.nowcoder.com/acm/contest/53254/K

题目描述:

JJZ 也是一个农批,她想上巅峰 2100,但是 JJZ 总是先输一局再赢一局。

输 —— 赢 —— 输 —— 赢 —— 输” 如此循环。

JJZ 是一个稳妥的人类,如果JJZ 的巅峰分大于等于2100 时,JJZ 将不会进行下一局游戏。假设 JJZ 输一局会减 10 分,赢一局加 15 分。JJZ 目前为 k 分,且上一局为输,请你帮帮 JJZ :求出她还需要打多少局,巅峰分才会至少为 2100。 

输入描述:

 输出描述:

 输入输出:

 思想:这个题目感觉应该是到签到题,比较简单,就是一个简单的模拟就好;

就是设置一个标记,来标记出赢一局和输一局,这样在循环中,就能直接暴力出来了,没啥好讲的。

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    long long k;
    int flag=1;
    cin>>k;
    int cnt=0;
    if(k>=2100)
    {
        cout<<cnt;
        return 0;
    }
    else
    {
        while(k<2100)
        {
            if(flag==1)//赢的时候,flag就是1
            {
                k+=15;
                cnt++;
                flag=0;//接下来一句就输掉,所以flag改变为0
            }
            else
            {
                k-=10;
                cnt++;
                flag=1;
            }
        }
    }
    cout<<cnt;
    return 0;
}

以上就是ccsu训练赛的A、C、E、F、I、J、K的题解了,剩下的题目周末补完题目再写,嘿嘿。

最后就是:

 大佬捞捞我,嘿嘿;

不懂的可以评论区一起讨论讨论,嘻嘻!!!

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值