yukicoder No.3037 Restricted Lucas (Hard)

Easyも全く同じコードで通るのでまとめて。

問題概要

Lucas数(0項目が2、1項目が1のフィボナッチ数)のN項目を10億7で割った余りを求めるクエリT個を解いてください。
Easy:「0123456789\"'*/%」が使用禁止でT≦100、1≦N≦2000000000
No.3036 Restricted Lucas (Easy) - yukicoder
Hard:Easyに加えて「+-」も使用禁止。代わりにT≦10に。
No.3037 Restricted Lucas (Hard) - yukicoder

解説

evalって便利ですよね。ってことで頑張って回避して「*、%」の文字コード42と37を作ったら文字列をつなげてはevalに投げることを繰り返します。普通の最小二乗法を利用すればOK。

で、言語にもよりますが、Pythonなら1=int(not None)、0=int(not not None)なので、Easyは文字列の連結が+で出来るので適当に42,37と1000000007を作ってやるだけです。因みにRubyなら0=nil.to_i、-1=~nil.to_iで、宇宙演算子を使って1=nil.to_i<=>~nil.to_iで表現できます。(ただ、evalでの返り値の返し方を知らないので)

Hardになると、+-が使用不可になるので、ビット演算で頑張って42,37,1000000007に加えて「+」の文字コード43も作ります。-は-1をかければいいのでスルー。文字列の連結を行う際は「演算を行うため」という用途に限られる=数字の間に必ず演算子が入るので、例えば"a+b"→"+".join([a,b])みたいに置き換えると幸せになれます。

https://yukicoder.me/submissions/249560

two = int(not None)<<int(not None)
cross = ((two<<two)<<two)|(two<<two)|two
plus = cross|int(not None)
percent = ((two<<two)<<two) | (two<<int(not None)) | int(not None)
three = two | int(not None)
four = int(not None)<<two
seven = four | two | int(not None)
sixteen = int(not None)<<four
mod = (seven<<((three<<three)|three)) | (seven<<((int(not None)<<four) | seven)) | (three<<((int(not None)<<four)|three)) | (int(not None)<<((int(not None)<<four)|int(not None))) | (three<<(seven<<int(not None))) | ((four|int(not None))<<(four<<int(not None)|int(not None))) | seven
def mul(a,b):
    ret=[]
    for i in range(len(a)):
        append=[]
        for j in range(len(b[int(not(not None))])):
            add = int(not(not None))
            for k in range(len(a[i])):
                add = eval(chr(plus).join([str(add),chr(cross).join([str(a[i][k]),str(b[k][j])])]))
                add = eval(chr(percent).join([str(add),str(mod)]))
            append.append(add)
        ret.append(append)
    return ret
def solve(n):
    a = [[int(not None), int(not None)], [int(not None), int(not(not None))]]
    ret = [[int(not None)],[two]]
    n = eval(chr(plus).join([str(n),str(~int(not not None))]))
    while n>int(not(not None)):
        if n & int(not None):
            ret = mul(a,ret)
        a=mul(a,a)
        n>>=int(not None)
    return ret[int(not not None)][int(not(not None))]
t=int(input())
for i in range(t):
    n=int(input())
    print(solve(n))

感想

本当は載せるつもり無かったんですが、Hard解き終えた後に解説見て「アレ?eval問じゃない?」ってなったので。