SRM585 Div1 Medium(500) LISNumber
動的計画法。小さい順にn枚のカードを選んだとき、a[i]≧a[i+1]となるiがちょうどk個になる並べ方の数を覚えておく。これは同じ数字のカードを区別した場合の数なので、最後に数字ごとにその数字のカードの枚数の階乗で割る。法Mが素数ならば、1/x = xM-2になる。Pythonならば、pow(x,M-2,M)で高速に計算できる。
class LISNumber: def count(self, cardsnum, K): M = 1000000007 S = sum(cardsnum) if K>S: return 0 T = [1]+[0]*S l = 0 for c in cardsnum: for i in range(c): P = T T = [0]*(S+1) for k in range(S): T[k] = (T[k]+P[k]*(k-i+1))%M T[k+1] = (T[k+1]+P[k]*(l-k+i))%M l += 1 ans = T[K-1] for c in cardsnum: t = reduce(lambda a,b: a*b%M, range(1,c+1)) ans = ans*pow(t,M-2,M)%M return ans