您的位置:首页 > 运维架构

Topcoder:SRM 708 算法题解

2017-02-11 11:21 369 查看

题目翻译

250分题目:SafeBetting

赌徒有b块钱,他想把自己手上的钱增加到c块,同时他又不想输的太惨,因此必须保证每次下注后手上不少于a块钱。每次下注,赢了则下注的钱按双倍奉还(收益率100%),输了则分文不剩(收益率-100%)。问赌徒至少需要下注几次才能达到目标。

500分题目:BuildingStrings

定义一个字符串的得分score为:字符串长度length与字符串中不同的字母的个数unique_num的乘积。给定一个总分K,求一系列字符串使得他们的得分的总和为K。要求每个字符串由小写英文字母组成,长度不超过50。当有多个答案时,任意输出一个即可。

1000分题目:PalindromicSubseq2

给定一个字符串S,其中的每个字母的得分X[i]由它左右两边的对称字符串的个数来决定(即左右两边的字符串s1=S[:i],s2=S[i+1:], 从s1中取子字符串s11,从s2中取子字符串s22,s11与s22排列相反)。定义Y[i] = ((i+1) * X[i]) modulo 1,000,000,007,求Y[i]按位异或后的值。

解题思路及代码

250分题解:SafeBetting

赌徒每次可以赚的钱的数目为手上的钱减去最低限度。设可用资金为M=b-a,可用目标资金 N=c-a, 则每次赌博可用资金增加一倍,输出为log(M/N,2)向上取整即可。

import math,string,itertools,fractions,heapq,collections,re,array,bisect
class SafeBetting:
def minRounds(self, a, b, c):
return math.ceil(math.log(float(c-a)/(b-a),2))


500分题解:BuildingStrings

这是一个构造问题,只需要进行构造即可。先构造几个基础字符串,再将得分分解为这些基础字符串的和即可。每个字符串最长为50,最多有26个独特字母,最高得分为50×26=1300分。因此构造的时候,可以构造三种字符串:1300分的字符串,50×m(m<26)分的字符串,n(n<50)分的字符串。将每中得分进行分解即可。

class BuildingStrings:
def findAny(self, K):
S_26='abcdefghijklmnopqrstuvwxyz'
S_1300='abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx'
N_1300=K/1300
K=K-N_1300*1300
N_50=K/50
K=K-N_50*50
N_1=K
ret=[]
ret+=[S_1300 for i in range(N_1300)]
if N_50>0:
S_50k=S_26[:N_50]+'a'*(50-N_50)
ret+=[S_50k]
#print ret
S_1='a'*N_1
ret+=[S_1]
#print ret
return tuple(ret)


1000分题解:PalindromicSubseq2

这个问题的主要难度在于求字符串S每个位置上的得分X[i],如果针对每个位置都进行一遍计算的话,在复杂情况下肯定会超时。容易联想到最长公共子序列问题中的动态规划算法(leetcode上有公共子序列个数的问题,题名Distinct Subsequences)。

如果之前求解过公共子序列个数的问题的话,这个问题可以看作公共子序列个数问题的改进版。

首先,回顾公共子序列个数问题:给定字符串S和T,求S和T中公共子序列的个数。利用动态规划来求解,S中前i个字母的子字符串S1,和T中前j个字母的字符串T1,dp[i][j]表示S1和T1中公共子序列的个数。

转移方程:dp[i][j]包含四个部分,公共子序列中同时包含S[i]和T[j],公共子序列中不含S[i]和T[j],公共子序列中包含S[i]不包含T[j],公共子序列中不包含S[i]包含T[j]。



则如果S[i]与T[j]相同,则dp[i][j]=dp[i-1][j]+dp[i][j-1]

如果S[i]与T[j]不相同,则dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]

依次计算dp即可。

接着,再将现在的问题转化为公共子序列的个数的问题。令S=S,T=S_reverse(S_reverse为S的逆序字符串),则X[i]=dp[i][n-i+1]。然后就是直接求解了。

class PalindromicSubseq2:
def dynamicplan(self,s):
N=len(s)
#dp={j:{i:0 for i in range(N) if i>j} for j in range(N)}
dp=[[0 for i in range(N)] for j in range(N)]
for i in range(N):
dp[i][N-1]=1
for j in range(N):
dp[0][j]=1
for i in range(1,N):
for j in range(N-2,i-1,-1):
if s[i-1]==s[j+1]:
dp[i][j]=dp[i-1][j]+dp[i][j+1]
else:
dp[i][j]=dp[i-1][j]+dp[i][j+1]-dp[i-1][j+1]
return dp
def solve(self, s):
N=len(s)
dp=self.dynamicplan(s)
count=0
for i in range(N):
X_i=dp[i][i]
#print X_i,
count_i=(i+1)*X_i%1000000007
count^=count_i
return count


思路是对的,但是python的运行速度实在太慢,能通过简单的测试,但是系统测试的时候有一个测试案例没有通过,程序运行了2.493s,导致超时了。看来遇到对运行速度有要求的题目,还是得拿C/C++来写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法