题目翻译
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++来写。