第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛

本文介绍了第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛的部分题目,包括跳台阶问题、psd面试的动态规划解法、等式求解、旋转矩阵模拟以及强迫症序列的操作步数计算。文章提供了详细思路和部分题目的解题链接。

A.跳台阶

链接:https://www.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:无后效性,dp

#include <cstdio>
#include <iostream>
using namespace std;
int t,n;
int f[35];
int main(){
    for (int i = 1;i <= 30;i++) f[i] = 1;
    for (int i = 2;i <= 30;i++){
        for (int j = 1;j < i;j++){
            f[i] += f[j];
        }
    }
    scanf("%d",&t);
    for (int i = 0;i < t;i++){
        scanf("%d",&n);
        printf("%d\n",f[n]);
    }
    return 0;
}

法2:每个台阶可以选择走或者跳过(不走该层),n层台阶有2^(n-1)种走法

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
int main(){
    int t,n;
    cin>>t;
     
    while(t--){
        cin>>n;
         
        printf("%lld\n",(ll)pow(2.0,n-1));
    }
    return 0;
}

D.psd面试

求除去最长回文子序列后还有多少字母(忽略大小写)

输入

google

输出

2

输入

aBc,bAd

输出

2

思路:

动态规划思想

对于任意字符串,如果头尾字符相同,那么字符串的最长子序列等于去掉首尾的字符串的最长子序列加上首尾;如果首尾字符不同,则最长子序列等于去掉头的字符串的最长子序列和去掉尾的字符串的最长子序列的较大者。

因此动态规划的状态转移方程为:

设字符串为str,长度为n,p[i][j]表示第i到第j个字符间的子序列的个数(i<=j),则:

状态初始条件:dp[i][i]=1 (i=0:n-1)

状态转移方程:dp[i][j]=dp[i+1][j-1] + 2  if(str[i]==str[j])

                   dp[i][j]=max(dp[i+1][j],dp[i][j-1])  if (str[i]!=str[j])

计算dp[i][j]时需要计算dp[i+1][*]或dp[*][j-1],因此i应该从大到小,即递减;j应该从小到大,即递增。

(时间复杂度O(n^2)),空间复杂度O(n^2))

(可用滚动数组进行空间优化)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
string s;
int dp[1500][1500] = {0};
int LPS(string s){
	int n = s.length(); 
    for (int i = n-2;i >= 0;i--){
        for (int j = i + 1;j < n;j++){
            if (s[i] == s[j]){
                dp[i][j] = dp[i+1][j-1] + 2;
            }else{
                dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
            }
        }
    }
    return dp[0][n-1];
}

int main(){
    while(cin >> s){
        for (int i = 0;i < s.length();i++) {
            dp[i][i] = 1;
            if (s[i] >= 'A' && s[i] <= 'Z') 
                s[i] -= 'A' - 'a';
        }
        cout << s.length() - LPS(s) << endl;
    }
    return 0;
}

F.等式

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

输入

3

1

20180101

1000000000

输出

1

5

181

对方程变形得到:n^2=a*b

设n^2的因子个数为p,n^2的所有因子中除n外都是成对出现的,故方程解数为(p+1)/2。

现设法求n^2的因子个数

根据约数个数定理:n=p1^a1×p2^a2×p3^a3*…*pk^ak,n的约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1).

因为pk在n^2中出现次数为n中出现次数的2倍,故只需算n的因子个数,再×2即可

#include <iostream>
#include <cstring>
using namespace std;
int num[64];//对应约数个数定理中的ai

int main()
{
	int cases,t=0;
	scanf("%d",&cases);
	while(cases--){
		int n,p=0;
		memset(num,0,sizeof(num));
		scanf("%d",&n);
		for(int i=2;i*i<=n;++i){
			if(n%i==0){
				while(n%i==0){
					++num[p];
					n/=i;
				}
				++p;
			}
		}
		if(n!=1){
			++num[p];	
			++p;
		}
		for(int i=0;i<p;++i)
			num[i]*=2;
		int ans=1;
		for(int i=0;i<p;++i)
			ans*=(num[i]+1);
		printf("%d\n",(ans+1)/2);
	}
} 

G.旋转矩阵

链接:https://www.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
|+|
+-+

备注:

左旋即逆时针旋转,右旋即顺时针旋转

-通过一次左旋或右旋会变成|

|通过一次左旋或右旋会变成-


简单的模拟

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int T,n,m;
char map[35][35];
string s;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for (int i = 0;i < n;i++){
            for (int j = 0;j < m;j++){
                cin >> map[i][j];
            }
        }
        cin >> s;
        int num = 0;
        for (int i = 0;i < s.length();i++){
            if (s[i] == 'L') num = (num + 1) % 4;
                else num = (num + 3) % 4;
        }
        if (num == 0){
            printf("%d %d\n",n,m);
            for (int i = 0;i < n;i++){
                for (int j = 0;j < m;j++){
                    printf("%c",map[i][j]);
                }
                puts("");
            }
            puts("");
        }
        if (num == 1){
            printf("%d %d\n",m,n);
            for (int i = 0;i < m;i++){
                for (int j = 0;j < n;j++){
                    //printf("%c",map[n-1-j][i]);
                    if (map[j][m-1-i] == '-') printf("|");
                    else if (map[j][m-1-i] == '|') printf("-");
                    	else printf("%c",map[j][m-i-1]);
                }
                puts("");
            }
            puts("");
        }
        if (num == 2){
            printf("%d %d\n",n,m);
            for (int i = 0;i < n;i++){
                for (int j = 0;j < m;j++){
                    printf("%c",map[n-i-1][m-j-1]);
                }
                puts("");
            }
            puts("");
        }
        if (num == 3){
            printf("%d %d\n",m,n);
            for (int i = 0;i < m;i++){
                for (int j = 0;j < n;j++){
                    //printf("%c",map[n-j-1][i]);
                    if (map[n-j-1][i] == '-') printf("|");
                    else if (map[n-j-1][i] == '|') printf("-");
                    	else printf("+");
                }
                puts("");
            }
            puts("");
        }
    }
    return 0;
}

I.填空题

(这题太水了,就不po了)

J.强迫症的序列

链接:https://www.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操作里,所以最后所得

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int t,n;
int a[100005];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        int minn = 1005;
        for (int i = 0;i < n;i++){
            scanf("%d",&a[i]);
            minn = min(a[i],minn);
        }
        int ans = 0;
        for (int i = 0;i < n;i++){
            ans += a[i] - minn;
        }
        printf("%d %d\n",ans,ans+minn);
    }
    return 0;
}

L.用来作弊的药水

链接:https://www.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

数据比较弱,快速幂取余水过了...

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 999983;
int n,a,b,a1,b1;
long long modexp(long long a,long long b){
    long long res = 1;
    while (b){
        a %= mod;
        if (b & 1){
            res = res * a % mod;
            //cout << res;
        }
        a = a * a % mod;
        b = b >> 1;
        //cout << res;
    }
   // cout << res;
    return res;
}
int main(){
    scanf("%d",&n);
    for (int i = 0;i < n;i++){
        scanf("%d%d%d%d",&a,&a1,&b,&b1);
        if (modexp(a,a1) == modexp(b,b1)){
            puts("Yes");
        }else puts("No");
    }
    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;//int   -2147483648~2147483647 
        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;
}
#include <cstdio>  
#include<algorithm>  
#include<math.h>  
using namespace std;  
int gcd(int a,int b){  
 if(a%b==0)  
  return b;  
 return gcd(b,a%b);  
}  
int main()  
{  
    int n,T,x,a,y,b;  
    scanf("%d",&T);  
    while(T--)  
    {  
        scanf("%d%d%d%d",&x,&a,&y,&b);  
        int ab=gcd(a,b);  
        int xy=gcd(x,y);  
        a/=ab;  
        b/=ab;  
           
        if(fabs(pow(1.0*x,1.0*a)-pow(1.0*y,1.0*b))<0.0001)  
            printf("Yes\n");  
        else 
            printf("No\n");  
       // printf("%d %d",x,y);  
    }  
    return 0;  
}

以上为场上A掉的题的题解,没A掉的题以后补

不过E题那么水都没A掉真是一大耻辱...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值