1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| from gmpy2 import invert def _int32(x): return int(0xFFFFFFFF & x) class mt19937: def __init__(self, seed=0): self.mt = [0] * N self.mt[0] = seed self.mti = 0 for i in range(1, N): self.mt[i] = _int32(F * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i) def getstate(self,op=False): if self.mti == 0 and op==False: self.twist() y = self.mt[self.mti] y = y ^ y >> U y = y ^ y << S & B y = y ^ y << T & C y = y ^ y >> L self.mti = (self.mti + 1) % N return _int32(y) def twist(self): for i in range(0, N): y = _int32((self.mt[i] & 0x80000000) + (self.mt[(i + 1) % N] & 0x7fffffff)) self.mt[i] = (y >> 1) ^ self.mt[(i + M) % N] if y % 2 != 0: self.mt[i] = self.mt[i] ^ A def inverse_right(self,res, shift, mask=0xffffffff, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp >> shift & mask return tmp def inverse_left(self,res, shift, mask=0xffffffff, bits=32): tmp = res for i in range(bits // shift): tmp = res ^ tmp << shift & mask return tmp def extract_number(self,y): y = y ^ y >> U y = y ^ y << S & B y = y ^ y << T & C y = y ^ y >> L return y&0xffffffff def recover(self,y): y = self.inverse_right(y,L) y = self.inverse_left(y,T,C) y = self.inverse_left(y,S,B) y = self.inverse_right(y,U) return y&0xffffffff def setstate(self,s): if(len(s)!=N): raise ValueError("The length of prediction must be N!") for i in range(N): self.mt[i]=self.recover(s[i]) self.mti=0 ''' def predict(self,s): # a method to predict other pseudo random numbers after given N of them (useless in this problem) self.setstate(s) self.twist() return self.getstate(True) ''' def invtwist(self): high = 0x80000000 low = 0x7fffffff mask = A opt = [0] * 4 for i in range(N-1,N-2,-1): for s in range(2): for t in range(2): tmp = self.mt[i]^self.mt[(i+M)%N] if s==0: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 res = tmp&high tmp = self.mt[i-1]^self.mt[(i+M-1)%N] if t==0: tmp ^= mask tmp <<= 1 tmp |= 1 else: tmp <<=1 res |= (tmp)&low opt[s * 2 + t] = res return opt def recover_seed(self,last): n = 1 << 32 inv = invert(F, n) for i in range(N-1, 0, -1): last = ((last - i) * inv) % n last = self.inverse_right(last, 30) return last
N, M, A, U, S, B, T, C, L, F = map(int, input().split()) inpt = [0] * N for i in range (N): inpt[i] = int(input()) D = mt19937() D.setstate(inpt) op = D.invtwist() seed = [0] * 4 for i in range(4): seed[i] = D.recover_seed(op[i]) E = mt19937(seed[i]) E.getstate() flag = 1 for j in range(10): if E.extract_number(E.mt[j]) != inpt[j]: flag = 0 if flag > 0: print(seed[i]) break
|