第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛 个人笔记 题解

题目链接:https://ac.nowcoder.com/acm/contest/90#question

 

A.跳台阶

链接:https://ac.nowcoder.com/acm/contest/90/A
来源:牛客网

题目描述

有一个n级台阶的楼梯,小明一次可以向上跳1步,两步,甚至是n步,请问小明跳到n级台阶有多少种跳法?

输入描述:

第一行输入一个整数t,代表有t组样例:( T<=30)
接下来的t行,都用一个整数n,表示楼梯有n级台阶( 1<=n<=30)

输出描述:

输出跳到第n级台阶有多少种跳法

示例1

输入

复制

1
1

输出

复制

1

 有2种做法,第一种暴力dp,dp[i]+=dp[j],j为1~i-1复杂度O(n^2),第二种推公式dp[i]=2*dp[i-1]

f(n) = f(n-1)+f(n-2)+f(n-3)+......+f(n-n)=f(0)+f(1)+f(2)+......+f(n-1)
又因为f(n-1)=f(0)+f(1)+f(2)+.......+f(n-2)
两式相减得:f(n)-f(n-1)=f(n-1)得到 Fib(n) = 2*Fib(n-1)  (n >= 2)

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

int main(){
    long long dp[35];
    int T,n;

    scanf("%d",&T);

    while(T--){
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        dp[1]=1;
        for(int i=2;i<=n;i++)
            dp[i]=2*dp[i-1];
//        for(int i=1;i<=n;i++)
//            for(int j=0;j<i;j++)
//                dp[i]+=dp[j];

        printf("%lld\n",dp[n]);
    }



    return 0;
}

B.跳一跳,很简单的

链接:https://ac.nowcoder.com/acm/contest/90/B
来源:牛客网
 

题目描述

有一无限循环字母表:

现在有一棵n个节点(编号1-n)的有根树(1为根),树边边权为一个字母θ,在每一时刻θ会向前跳K步变为相应字母(即树边边权改变),如:

n每一时刻会向前跳3步,第1时刻变为q,第2时刻变为t,以此类推。

w每一时刻会向前跳2步,第1时刻变为y,第2时刻变为a,以此类推。

JK会给你Q个询问,让你判断两个节点在t时刻到根节点路径权值(路径权值为该节点到根节点的路径上字母按顺序拼成的字符串)的字典序大小关系。

输入描述:

第一行一个整数T(0<T<3),代表测试数据组数。
每一组测试数据第一行给出树的节点数n(1<n<=100000)。
接下去的n-1行的第i行给出一个整数P(1<=P<=n),一个字母θ([a-z])以及字母变换的步数K(0<=K<=10000),表示编号为i+1的节点的父亲节点编号为P,以及边的描述。(输入保证为一棵树)
下一行询问数Q(0<Q<=10000),每个询问一行给出整数u(2<=u<=n),v(2<=v<=n),t(0<=t<=10000),判断编号为u,v两个节点在t时刻到根节点路径权值的字典序大小关系。

输出描述:

对每个询问输出一行答案,
编号u到根节点路径权值的字典序小于v的输出“<”,
相等输出“=”,
否则输出“>”。(不包含该引号)

示例1

输入

复制

1
10
1 a 1
1 a 5
1 c 2
2 f 2
3 a 5
3 e 3
4 b 1
5 z 1
7 o 2
4
5 7 0
5 7 2
9 10 1
8 8 8

输出

复制

>
<
<
=

通过率低,有空去补

 

C.平分游戏

链接:https://ac.nowcoder.com/acm/contest/90/C
来源:牛客网
 

题目描述

集训队一共有n位同学,他们都按照编号顺序坐在一个圆桌旁。第i位同学一开始有a[i]个硬币,他们希望使得每位同学手上的硬币变成相同的数目。每一秒钟,有且仅有一位同学可以把自己手上的一枚硬币交给另一位同学,其中这两位同学中间必须间隔k位同学。

现在问的是最少几秒后所有同学手上的有相同数量的硬币

输入描述:

第一行输入两个整数n,k(1<=n<=1000000,0<=k<=n)
接下来的一行有n个整数,第i个整数a[i](0<=a[i]<=1e9)表示第i位同学手上的硬币的数量。

输出描述:

一个整数,表示最少几秒后所有同学手上的有相同数量的硬币。如果不可能,则输出gg。

示例1

输入

复制

5 0
2 3 1 5 4

输出

复制

3

 

D.psd面试

链接:https://ac.nowcoder.com/acm/contest/90/D
来源:牛客网
 

题目描述

然而面试官 xwc 一眼就看到了重点:大学打过 ACM!
xwc:“
    听说你很低袄?考你个题:
    忽略字母大小写,你这篇简历去掉最长的回文子序列后还有多长?

psd 顺手就把这个问题抛给了你。

输入描述:

多组输入,每组输入一个长度不超过 1234 的没空格的字符串,是 psd 的简历。

输出描述:

每组输出一个整数,如题。

示例1

输入

复制

google

输出

复制

2

示例2

输入

复制

aBc,bAd

输出

复制

2

 题目废话很多,适当删减

区间dp,LIS最长公共子序列变形

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int dp[2005][2005];

int main(){
    string s;
    while(cin>>s){
        int n = s.size(),j,k;
        transform(s.begin(),s.end(),s.begin(),::tolower);

        for(int i=0;i<n;i++)
            dp[i][i] = 1;

        for(int len=2;len<=n;len++)
            for(int i=0;i<n-len+1;i++){
                int j = i+len-1;
                if(s[i]==s[j])
                    dp[i][j] = 2 + dp[i+1][j-1];
                else
                    dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
            }

        cout<<n-dp[0][n-1]<<endl;
    }

	return 0;
}

 

 

E.回旋星空

链接:https://ac.nowcoder.com/acm/contest/90/E
来源:牛客网
 

题目描述

曾经有两个来自吉尔尼斯的人(A和C)恋爱了,他们晚上经常在一起看头上的那片名为假的回旋星空,

有一天他们分手了,A想通过回旋星空测量他们之间的复合指数,测量的规则是,

计算回旋图标的个数,即选中三颗星星,分别作为回旋图标的起点,拐点和终点,假设现在有三个

星星分别为i,j,k,如果d(a[i],a[j]) == d(a[j],a[k])则表示找到了一个回旋图标,其中d(x,y)表示这两个点的欧氏距离

为了给它很大的希望(i,j,k)和(k,j,i)被认为是两个不同的回旋图标

 

A花了一晚上终于把整片星空映射到了一张二平面图上,由于星星太多以至于A有点懵逼,所以

你能帮帮他吗,要不然他可能真的WA的一声哭了出来

作为埃森哲公司的一员,你在解决问题的同时也向A介绍了埃森哲公司的业务范围。

为了全方位地满足客户的需求,正在不断拓展自身的业务服务网络,包括管理及信息技术咨询、企业经营外包、企业联盟和风险投资。除了以产品制造业、通信和高科技、金融服务、资源、政府机构等不同行业划分服务内容之外,还从以下几方面提供咨询服务:
1.客户关系管理
2.业务解决方案
3.电子商务
4.供应链管理
 

输入描述:

 

第一行一个整数T(T<=10),表示组数

对于每组数据有一个n,表示有n个小星星(0< n < 1000)

接下来跟着n行,每行跟两个整数xi和yi表示每个星星的坐标(-10000< xi, yi<10000)

输出描述:

对于每组数据,如果没有找到回旋图标输出”WA”,否则输出找到图标个数

示例1

输入

复制

2
2
1 0
0 1
3
1 0
0 1
0 0

输出

复制

WA
2

备注:

没有重复的星星,且选中的三个星星是互相不一样的(即下标不同)
欧氏距离即直线距离

思维,排列组合,几何

从暴力枚举每3个点转化为枚举每2个边,降低了复杂度,从O(n^3)->O(n^2)
每一次计算有多少种组合时,必须是在第一个for内结算,这样才能保证每2个边是相邻的,最后因为每2边交换也算一种方案,所以用A(n,2),而不用C(n,2),当然最后乘2也是可以的,比如有3个相同的边,公式就是3*2=6,把所以的这种方案数累加即可

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;


typedef long long ll;
int x[1005],y[1005];
int T,n;

int main(){
    scanf("%d",&T);

    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&x[i],&y[i]);
        ll ans=0;
        for(int i=0;i<n;i++){
            vector<int> dis;
            for(int j=0;j<n;j++)
                if(i!=j)
                    dis.push_back((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
            sort(dis.begin(),dis.end());
            for(int l=0,r=0;l<dis.size();l=r){
                while(r<dis.size() && dis[l]==dis[r])
                    r++;
                ans+=(r-l)*(r-l-1);//排列A n 2
            }
        }

        if(ans==0)
            printf("WA\n");
        else
            printf("%lld\n",ans);
    }

	return 0;
}

 

F.等式

链接:https://ac.nowcoder.com/acm/contest/90/F
来源:牛客网
 

题目描述

给定n,求1/x + 1/y = 1/n (x<=y)的解数。(x、y、n均为正整数)

 

输入描述:

在第一行输入一个正整数T。
接下来有T行,每行输入一个正整数n,请求出符合该方程要求的解数。
(1<=n<=1e9)

输出描述:

输出符合该方程要求的解数。

示例1

输入

复制

3
1
20180101
1000000000

输出

复制

1
5
181

数论,唯一分解定理
1/x+1/y=1/n,设x=n+a,y=n+b,化简可得n^2=a*b,
找出n^2的所有因子,根据数论中的唯一分解定理可得
任何整数n都可以表示为 n = p1^e1*p2^e2*..pn^en,
其中p1,p2…,pn都为素数,并且n的约数个数为(1+e1)*(1+e2)*…(1+en),
所以n^2 = (p1^e1*p2^e2…pn^en)^2 = (p1^2e1)*(p2^2e2)…*(pn^2en),所以因子个数为(1+2e1)*(1+2e2)*…(1+2en),所以可以利用唯一分解定理求出e1 e2…en,由于要满足x <= y所以只需找出a <= b的解的个数即可,设因子乘积为res,x<=y,所以res/2+1。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int num[2005];
int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int cnt=0;
        memset(num,0,sizeof(num));
        for(int i=2;i*i<=n;i++)
            if(n%i==0){
                while(n%i==0){
                    num[cnt]++;
                    n/=i;
                }
                cnt++;
            }

        if(n!=1){
            num[cnt]++;
            cnt++;
        }
        long long ans=1;
        for(int i=0;i<cnt;i++)
            ans*=(2*num[i]+1);
        printf("%lld\n",ans/2+1);
    }

	return 0;
}

 

G.旋转矩阵

链接:https://ac.nowcoder.com/acm/contest/90/G
来源:牛客网
 

题目描述

景驰公司自成立伊始,公司便将“推动智能交通的发展,让人类的出行更安全,更高效,更经济,更舒适”作为公司使命,通过产业融合、建设智能汽车出行行业的方式,打造“利国、利民、利公司、利个人”的无人驾驶出行系统。公司的愿景是成为中国第一、世界一流的智能出行公司。

有一天,景驰公司的工程师在真车上做测试。

景驰公司的试验车上面有一个奇怪的图案,这是一个n*m的矩阵,这辆车可以到处开,每次可以左旋右旋,小明想知道转完之后的图案是怎么样的

具体来说:有一个n*m的字符矩阵,只包含3种字符(‘+’‘-’,‘|’),通过一通乱旋之后变成什么样子?

输入描述:

第一行测试样例数T(0<T<=100)
每个测试样例第一行两个正整数n,m(0<n,m<=30)
接下来的n行是一个n*m的字符矩阵
字符矩阵之后是一串只包含‘L’(左旋)和‘R’(右旋)的字符串,长度不超过1000
每个样例间输出一个空行

输出描述:

第一行两个正整数n,m
接下来的n行是一个n*m的字符矩阵
每个样例后面输出一个空行

示例1

输入

复制

2
2 3
+-+
|+|
LLRRR

3 2
-+
+|
-+
LLL

输出

复制

3 2
-+
+|
-+

2 3
|+|
+-+

备注:

左旋即逆时针旋转,右旋即顺时针旋转
-通过一次左旋或右旋会变成|
|通过一次左旋或右旋会变成-

简单的模拟题,记录旋转的次数,每4次R就回到原处,说明可以模4,L就--,R就++,除了0和180度外,其他都需要'|','-'的交换,最后别忘了每个样例之后输出一个空行= =

#include<iostream>
#include<cstdio>
using namespace std;

char ch[35][35];
int T,n,m,x;

int main(){
    cin>>T;

    while(T--){
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>ch[i][j];
        x=0;
        string s;
        cin>>s;
        for(int i=0;i<s.size();i++)
            if(s[i]=='L')
                x--;
            else if(s[i]=='R')
                x++;
        x=(x%4+4)%4;

        if(x==0){
            cout<<n<<" "<<m<<endl;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++)
                    cout<<ch[i][j];
                cout<<endl;
            }
        }else if(x==1){
            cout<<m<<" "<<n<<endl;
            for(int i=1;i<=m;i++){
                for(int j=n;j>=1;j--)
                    if(ch[j][i]=='+')
                        cout<<ch[j][i];
                    else if(ch[j][i]=='-')
                        cout<<'|';
                    else
                        cout<<'-';
                cout<<endl;
            }
        }else if(x==2){
            cout<<n<<" "<<m<<endl;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++)
                    cout<<ch[n-i+1][m-j+1];
                cout<<endl;
            }
        }else{
            cout<<m<<" "<<n<<endl;
            for(int i=m;i>=1;i--){
                for(int j=1;j<=n;j++)
                    if(ch[j][i]=='+')
                        cout<<ch[j][i];
                    else if(ch[j][i]=='-')
                        cout<<'|';
                    else
                        cout<<'-';
                cout<<endl;
            }
        }
        cout<<endl;
    }

	return 0;
}

 

H.哲哲的疑惑

链接:https://ac.nowcoder.com/acm/contest/90/H
来源:牛客网
 

题目描述

哲哲有l个球,球是不同的,现在她要用n种颜色给它们染色,如果一种染色方案有k种颜色没有用到,那么哲哲会产生C(k,m)的不满意度。
现在哲哲想求所有方案的不满意度之和,然而她只知道1+1=9,而她的神犇朋友maple去FW战队当中单了不在她身边,所以并不会求,你能帮帮她吗?

输入描述:

三个数n,m,l
1<=n,m<=10^7,l<=10^18

输出描述:

一个数(对998244353取模),表示所有方案的不满意度之和

示例1

输入

复制

3 2 2

输出

复制

3

说明

有以下方案:
两个球同色,有2种颜色没有用到,哲哲产生C(2,2)=1的不满意度,然后这里有三种方案,共产生3的不满意度
两个球不同色,有1种颜色没有用到,哲哲很开心(*^▽^*)
所以总共产生3的不满意度

示例2

输入

复制

1634 1542 130

输出

复制

93812204

通过很低的组合数学

 

I.填空题

这题没有营养,直接输出ac就好

 

 

J.强迫症的序列

链接:https://ac.nowcoder.com/acm/contest/90/J
来源:牛客网
 

题目描述

牛客网是IT求职神器,提供海量C++、JAVA、前端等职业笔试题库,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的编程。作为acmer的小A,牛客网是他首选的题库。

小A是一个中度强迫症患者,每次做数组有关的题目都异常难受,他十分希望数组的每一个元素都一样大,这样子看起来才是最棒的,所以他决定通过一些操作把这个变成一个看起来不难受的数组,但他又想不要和之前的那个数组偏差那么大,所以他每次操作只给这个数组的其中n-1个元素加1,但是小A并不能很好的算出最优的解决方案,如果你能帮他解决这个问题,小A就能送你一个气球

输入描述:

 

第一行一个整数T(T<=100),表示组数

对于每组数据有一个n,表示序列的长度(0< n <100000)

下面一行有n个数,表示每个序列的值(0<ai<1000)

输出描述:

输出两个数
第一个数表示最小的操作步数
第二个数经过若干步以后的数组元素是什么

示例1

输入

复制

1
3
1 2 3

输出

复制

3 4

 思维,贪心

每次操作n-1个数+1,可以等价于1个数-1,这样复杂度就从O(n)降到O(1)了,最小的数不会再减少了,再反过来思考,操作了多少次其实最小的数就会加多少,而这个数就是最后稳定的数

#include<iostream>
#include<cstdio>
using namespace std;

int main(){
    int T,n;
    int a[100005];
    scanf("%d",&T);

    while(T--){
        int ans=0,m=9999;
        scanf("%d",&n);

        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            m = min(m,a[i]);
        }

        for(int i=1;i<=n;i++)
            ans+=a[i]-m;

        printf("%d %d\n",ans,m+ans);

    }

	return 0;
}

 

 

K.密码

链接:https://ac.nowcoder.com/acm/contest/90/K
来源:牛客网
 

题目描述

ZiZi登录各种账号的时候,总是会忘记密码,所以他把密码都记录在一个记事本上。其中第一个密码就是牛客网的密码。

牛客网专注于程序员的学习、成长及职位发展,连接C端程序员及B端招聘方,通过IT笔试面试题库、在线社区、在线课程等提高候选人的求职效率,通过在线笔试、面试及其他工具提升企业的招聘效率。

团队由来自Google、百度、阿里、网易等知名互联网巨头的热血技术青年组成,用户覆盖全国2000多所高校的100W求职程序员及全部一线互联网企业,并仍在高速增长中。

谨慎的ZiZi当然不会直接把密码记录在上面,而是把上面的字符串经过转化后才是真正的密码。转化的规则是把字符串以n行锯齿形写出来,然后再按从左到右,从上到下读取,

即为真正的密码。如ABABCADCE以3行写出:

  

所以真正的密码是ACEBBACAD。但是每一次都要写出来就太麻烦了,您如果能帮他写出一个转换程序,他就送你一个气球。

输入描述:

第一行一个整数T,表示数据组数
对于每组数据,首先一个正整数n(n<=100,000),然后下一行为一个字符串,字符串长度len<=100,000。

输出描述:

对于每组数据,输出一个字符串,代表真正的密码。

示例1

输入

复制

1
3
ABABCADCE

输出

复制

ACEBBACAD

找规律,分别写n=3,4,5,6的情况,你会发现除了第一行和最后一行是均匀2*n-2,其他的步数都是2*(n-i-1)与2*i交替 

#include<stdio.h>
#include<string.h>
#include<string>
using namespace std;
 
char s[100005];
 
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %s",&n,s);
        if(n==1)
        {
            printf("%s\n",s);
            continue;
        }
        int len=strlen(s);
        string res;
        for(int i=0;i<n;i++){
            int k=i;
            if(i==0||i==n-1){
                while(k<len){
                    res+=s[k];
                    k+=2*n-2;
                }
            }
            bool flag=true;
            while(k<len){
                res+=s[k];
                k+=flag?2*(n-i-1):2*i;
                flag=!flag;
            }
        }
        printf("%s\n",res.c_str());
    }
    return 0;
}

 

 

 

L.用来作弊的药水

链接:https://ac.nowcoder.com/acm/contest/90/L
来源:牛客网
 

题目描述

    在一个风雨交加的夜晚,来自异世界的不愿透露姓名的TMK同学获得了两种超强药水A、B。根据说明书,TMK知道了这两种药水的作用:
    (1)药水A能使人的生命值提高,每饮用1个单位能使他生命值变成原来的x倍,即每饮用p个单位能使他的生命值变成原来的x^p(x的p次方)倍。
    (2)药水B能使人的能量值提高,每饮用1个单位能使他能量值变成原来的y倍,即每饮用q个单位能使他的能量值变成原来的y^q(y的q次方)倍。
    于是TMK迫不及待地喝下了所有的a个单位的药水A和b个单位的药水B,他立马体会到了自己能力的超强变化,然后他看了接下来的说明书:
    药水A和药水B能互相抑制对方的负面效果,一旦生命值提升的倍数和能量值提升的倍数不相等,那么在五个小时后将会发生非常严重的后果。

    于是TMK同学慌了,他想知道自己提升的生命值和能量值的倍数是否相等,由于他非常慌张,所以他把计算的重任交给你了。

作为埃森哲公司的一员,你觉得这个问题很简单,这得益于埃森哲公司分享知识的文化。

   分享知识已成为埃森哲源远流长的文化。
   埃森哲公司在帮助客户进行行之有效的知识管理的同时,它的管理层在其内部也进行了成功的知识管理的实践。如今,在埃森哲,分享知识已成为其源远流长的文化。在很大程度上,埃森哲公司的成功得益于其强大的知识管理系统。

 

 

输入描述:

第一行一个整数T,代表有T组数据。(1<=T<=5000)
每组数据仅一行,包含四个整数x,a,y,b,意义为题目描述。(1<=x,a,y,b<=10^9)

输出描述:

每组数据输出一行"Yes"或"No"(不包含双引号),表示TMK提升的生命值和能量值的倍数是否相等,相等为"Yes",不相等为"No"。

示例1

输入

复制

4
2 20 4 10
20 20 20 20
20 21 21 20
32768 32768 1048576 24576

输出

复制

Yes
Yes
No
Yes

这里不处理浮点误差也可以AC,不过最好处理下,10^(-9)一遍用这个,还有大佬用对数AC

还可以直接快速幂暴力 x^a%mod==y^b%mod,分别模上1e9+7,虽然题目没说模后结果,但这里对很大的素数求模不会影响答案

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

int main(){
    int T;
    double x,a,y,b;
    scanf("%d",&T);
    while(T--){
        scanf("%lf%lf%lf%lf",&x,&a,&y,&b);
        double v = a/b;
        if(abs(pow(x,v)-y)<=0.0000001)
            printf("Yes\n");
        else
            printf("No\n");

    }

	return 0;
}

 

#include<bits/stdc++.h>
using namespace std;
typedef long double db;
const db eps=1e-9;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int x,a,y,b;
        scanf("%d%d%d%d",&x,&a,&y,&b);
        if(fabs(a*log(1.0L*x)-b*log(1.0L*y))<eps)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
/*
链接:https://www.nowcoder.com/acm/contest/90/L
来源:牛客网
 
4
2 20 4 10
20 20 20 20
20 21 21 20
32768 32768 1048576 24576
*/

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值