这是对牛客网举办的Nowcoder Girl的编程比赛的题目做一个题解。
1.勇气获得机
这题主要是为了判断奇偶性,一种逆序的思维,根据倒序的方法求出结果翻转之后便是正确答案。
代码如下:
#-*-coding:utf-8-*-
n=int(raw_input())
s=''
while(n>0):
if(n%2==0):
s+='G'
n=(n-2)/2
else:
s+='N'
n=(n-1)/2
print s[::-1]
2.排列
本题主要的题意就是使i位置上的数不等于i,因此对数组data采用遍历的方法,当data[i]=i+1时需要对i上面的数字相邻位置进行交换,理论上有几个data[i]=i+1的情况就需要交换几次,但是这里有种特殊情况,就是当data[i]=i+1并且满足data[i+1]=i+2时,虽然有两个值满足要求,但是由于是相邻的只需要交换一次即可。需要对这种情况进行讨论。即用i(i<n)表示数组的下标遍历数组,当没有相邻数字满足的时候,就每出现一次data[i]=i+1,将结果加1,同时i+=1;如果出现相邻数字满足时,结果加1,同时i+=2;依次遍历,直到遍历完数组。
#-*-coding:utf-8-*-
n=int(raw_input())
data=map(int,raw_input().split())
i=0
ans=0
while(i<n):
if(data[i]==i+1):
if(i+1<n and data[i+1]==i+2):
i+=2
ans+=1
else:
i+=1
ans+=1
else:
i+=1
print ans
3.打车
这题的思路比较明确就是先对拥有的硬币进行排序,因为需要的硬币个数越多越好,所以先从小到大进行加,但是当和大于s便停止加;又因为题目要求不能拿掉任意一个硬币还大于s;所以此时还需要遍历一遍已经加过的硬币,为了保证数量是最多的,应该从大到小遍历,避免减去一个稍微大的可以满足题目最终要求,但如果从小到大减则需要减大于1个小的,那么就使得结果不是最优解,因此应该从大到小遍历,判断拿掉当前硬币,是否还大于s,如果是则减去当前硬币,否则继续往前遍历。
# -*-coding:utf-8 -*-
n,s=map(int,raw_input().split())
coin=map(int,raw_input().split())
coin.sort()
sums=0
k=0
ans=0
while(k<n and sums<s):
sums+=coin[k]
k+=1
ans+=1
for i in range(k,0,-1):
if(sums-coin[i-1]>=s):
sums-=coin[i-1]
ans-=1
print ans
#求和应该从小到大加,然后减应该从大到小减
4.勇敢的妞妞
因为每一种装备都有五个属性,所以有一种情况很明确,就是当选取的装备件数大于等于5件的时候,只需要将每种属性的最大值相加即可。于是只需要讨论k<5的情况:当k=1只需要遍历求每种装备的属性和,取最大值即可;当k=2时,只需要使用i,j变量来控制任意两个装备,然后只需要将两者的每个属性的较大值相加即可,求出具有最大值的两两组合;当k=3,则利用i,j,h来控制三种装备,思路与k=2时差不多;重点是k=4,如果还用之前的思路,则必然会超时,这时候换种思路,不再控制装备,而是控制属性,因为属性只有五种,所以对时间影响不大,总的属性有五种,这时候需要选择四个装备,如果是五个装备,那么只需求每种属性的最大值即可,那么四个,则需要将其中的两个属性绑定在一起,另外三个则是求最大值,这样才能保证得到的是最大值,那么绑定的如何求呢?即遍历五种属性,外循环控制一种属性,内循环控制与之绑定在一起的属性,然后通过最内循环来控制装备,这样可以得到那种装备的那两种属性和是最大的,然后最内循环还需要加上剩下三种属性的最大值,并与结果比较大小,取大值。
首先是Python代码,该代码只能AC90%。
#-*-coding:utf-8-*-
def solve(n,w,s):
max_num=[0 for i in range(5)]
for i in range(n):
for j in range(5):
max_num[j]=max(s[i][j],max_num[j])
res=0
if(w==1):
for i in range(n):
temp=0
for j in range(5):
temp+=s[i][j]
res=max(res,temp)
elif(w==2):
for i in range(n):
for j in range(i+1,n):
temp = 0
for k in range(5):
temp+=max(s[i][k],s[j][k])
res=max(res,temp)
elif(w==3):
for i in range(n):
for j in range(i+1,n):
for k in range(j+1,n):
temp=0
for h in range(5):
temp+=max(s[i][h],s[j][h],s[k][h])
res=max(temp,res)
elif(w==4):#有一个装备肯定有两项技能和比较高,贪心
for i in range(5):
for j in range(i+1,5):
temp=0
for k in range(n):
temp=max(temp,s[k][i]+s[k][j])
for h in range(5):
if(k&i==0 and k&j==0):
temp+=max_num[h]
res=max(temp,res)
else:
for i in range(5):
res+=max_num[i]
return res
if __name__ == '__main__':
n,k=map(int,raw_input().split())
s=[]
for i in range(n):
w=map(int,raw_input().split())
s.append(w)
print solve(n,k,s)
然后根据以上同样的思路写的Java代码,AC了。
import java.util.*;;
public class Main {
public static int solve(int n,int k,int[][] s)
{
int res=0;
int[] max_num=new int[5];
for(int i=0;i<n;i++)
{
for(int j=0;j<5;j++)
max_num[j]=Math.max(s[i][j],max_num[j]);
}
if(k==1)
{
for(int i=0;i<n;i++)
{
int temp=0;
for(int j=0;j<5;j++)
{
temp+=s[i][j];
}
res=Math.max(temp, res);
}
}
else if(k==2)
{
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
int temp=0;
for(int h=0;h<5;h++)
{
temp+=Math.max(s[i][h], s[j][h]);
}
res=Math.max(temp, res);
}
}
}
else if(k==3)
{
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
for(int e=j+1;e<n;e++)
{
int temp=0;
for(int h=0;h<5;h++)
{
temp+=Math.max(s[i][h], Math.max(s[j][h], s[e][h]));
}
res=Math.max(temp, res);
}
}
}
}
else if(k==4)
{
for(int i=0;i<5;i++)
{
for(int j=i+1;j<5;j++)
{
int temp=0;
for(int e=0;e<n;e++)
{
temp=Math.max(temp, s[e][i]+s[e][j]);
}
for(int h=0;h<5;h++)
{
if(h!=i && h!=j)
temp+=max_num[h];
}
res=Math.max(res, temp);
}
}
}
else
{
for(int i=0;i<5;i++)
{
res+=max_num[i];
}
}
return res;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int k=sc.nextInt();
int[][] s=new int[n][5];
for(int i=0;i<n;i++)
{
for(int j=0;j<5;j++)
{
s[i][j]=sc.nextInt();
}
}
System.out.println(solve(n,k,s));
}
}
5.平方数
本题只需要将输入的开平方取整,然后再平方即可:
n=int(raw_input())
t=int(n**0.5)
print t*t
6.美丽的项链
本题是一个动态规划的题,这个题目就类似于凑钱的题目,只不过相当于给每种钱都添加了个数,而不是单纯的一个或0个;dp[i][j]表示前i种水晶宝珠能凑成j颗的方法数,当前i的宝珠颗数为li~ri,所以那么为了凑齐j颗,需要保证前i-1种宝珠需要凑齐多少颗(利用j与li、ri进行简单计算求得),求得一个范围都可以,那么只需要加上前i-1宝珠所有能满足需求的方案数。代码如下:
#-*-coding:utf-8-*-
l=[]
r=[]
n,m=map(int,raw_input().split())
for i in range(n):
li,ri=map(int,raw_input().split())
l.append(li)
r.append(ri)
ways=[[0 for i in range(m+1)] for j in range(n)]
for i in range(l[0],r[0]+1):
ways[0][i]=1
for i in range(1,n):
for j in range(m+1):
left=max(0,j-r[i])
right=max(0,j-l[i])#当前珠宝种类i的个数有li~ri个,所以前i种珠宝要凑成j个珠宝,则需要使得前i-1种凑成的珠宝数需要在left~right之间,
# 那么第i种才能够补上。
for k in range(left,right+1):
ways[i][j]+=ways[i-1][k] #ways[i][j]表示i种珠宝凑成j个珠宝的方法数,way[i-1][k]为前i-1种珠宝凑成k个的方法数
print ways[n-1][m]