3 import java
.math
.BigInteger
;
6 * Solution for NEERC'2009 Problem G: Garbling Game.
7 * This solution checks correctness of the input.
8 * @author Roman Elizarov
10 public class garbling_re
{
11 static final int MODULO
= 100000;
13 public static void main(String
[] args
) throws Exception
{
14 new garbling_re().go();
17 void go() throws Exception
{
23 static class Field
implements Cloneable
{
29 for (int i
= 0; i
< r
; i
++) {
30 for (int j
= 0; j
< c
; j
++) {
36 void garbleLeft(int i
, int j
) {
38 a
[i
][j
] = a
[i
][j
+ 1];
39 a
[i
][j
+ 1] = a
[i
+ 1][j
+ 1];
40 a
[i
+ 1][j
+ 1] = a
[i
+ 1][j
];
44 void garbleRight(int i
, int j
) {
46 a
[i
][j
] = a
[i
+ 1][j
];
47 a
[i
+ 1][j
] = a
[i
+ 1][j
+ 1];
48 a
[i
+ 1][j
+ 1] = a
[i
][j
+ 1];
58 BigInteger turns
= BigInteger
.ZERO
;
62 void read() throws Exception
{
63 Scanner in
= new Scanner(new File("garbling.in"));
64 in
.useLocale(Locale
.US
);
67 n
= new BigInteger(in
.next());
69 assert r
>= 2 && r
<= 300;
70 assert c
>= 2 && c
<= 300;
71 assert n
.compareTo(BigInteger
.ZERO
) >= 0 && n
.compareTo(BigInteger
.valueOf(10).pow(100)) < 0;
72 map
= new char[r
- 1][];
73 for (int i
= 0; i
< r
- 1; i
++) {
74 map
[i
] = in
.next().toCharArray();
76 assert map
[i
].length
== c
- 1;
77 for (int j
= 0; j
< c
- 1; j
++) {
78 assert "RLN".indexOf(map
[i
][j
]) >= 0;
87 writtenModulo
= new int[k
];
88 Field f
= new Field(r
, c
);
90 if (turns
.compareTo(n
) >= 0)
92 // find transposition of one garbling
93 int[] transpose
= new int[k
];
94 for (int i
= 0; i
< r
; i
++) {
95 for (int j
= 0; j
< c
; j
++) {
96 transpose
[f
.a
[i
][j
]] = i
* c
+ j
;
99 // split transposition into loops
100 int[] lnum
= new int[k
];
101 int[] llen
= new int[k
];
102 int[] lidx
= new int[k
];
103 int[][] lfromidx
= new int[k
][0];
104 int[][] lwrModulo
= new int[k
][0];
106 Arrays
.fill(lnum
, -1);
107 for (int p
= 0; p
< k
; p
++) {
113 lfromidx
[lc
] = grow(lfromidx
[lc
], cnt
+ 1);
114 lfromidx
[lc
][cnt
] = p
;
115 lwrModulo
[lc
] = grow(lwrModulo
[lc
], cnt
+ 2);
116 lwrModulo
[lc
][cnt
+ 1] = addModulo(lwrModulo
[lc
][cnt
], writtenModulo
[p
]);
119 } while (lnum
[p
] < 0);
123 woneModulo
= writtenModulo
.clone();
124 // fast-forward full-field grablings
125 BigInteger times
= n
.subtract(turns
).divide(turns
);
126 int[] lrem
= new int[k
+ 1];
127 int[] lfltModulo
= new int[k
+ 1];
128 Arrays
.fill(lrem
, -1);
129 for (int p
= 0; p
< k
; p
++) {
131 int pllen
= llen
[plnum
];
134 if (lrem
[pllen
] >= 0) {
136 plfltModulo
= lfltModulo
[pllen
];
138 BigInteger pllenBig
= BigInteger
.valueOf(pllen
);
139 BigInteger flt
= times
.divide(pllenBig
);
140 plrem
= lrem
[pllen
] = times
.mod(pllenBig
).intValue();
141 plfltModulo
= lfltModulo
[pllen
] = flt
.mod(BigInteger
.valueOf(MODULO
)).intValue();
143 writtenModulo
[p
] = addModulo(writtenModulo
[p
], mulModulo(plfltModulo
, lwrModulo
[plnum
][pllen
]));
144 int q
= transpose
[p
];
146 int idx2
= (idx1
+ plrem
) % pllen
;
147 q
= lfromidx
[plnum
][idx2
];
149 writtenModulo
[p
] = addModulo(writtenModulo
[p
], lwrModulo
[plnum
][idx2
] - lwrModulo
[plnum
][idx1
] + MODULO
);
150 else if (idx2
< idx1
)
151 writtenModulo
[p
] = addModulo(writtenModulo
[p
],
152 lwrModulo
[plnum
][pllen
] - lwrModulo
[plnum
][idx1
] + MODULO
+ lwrModulo
[plnum
][idx2
]);
153 f
.a
[q
/ c
][q
% c
] = p
;
155 turns
= turns
.add(times
.multiply(turns
));
156 // finish remaining garblings
158 assert turns
.equals(n
);
161 private int[] grow(int[] a
, int size
) {
162 return a
.length
>= size ? a
: Arrays
.copyOf(a
, Math
.max(size
, 2 * a
.length
));
165 void garbleFieldOnce(Field f
) {
166 for (int i
= 0; i
< r
- 1; i
++) {
167 for (int j
= 0; j
< c
- 1; j
++) {
168 if (turns
.compareTo(n
) >= 0)
170 turns
= turns
.add(BigInteger
.ONE
);
171 writtenModulo
[f
.a
[i
][j
]] = addModulo(writtenModulo
[f
.a
[i
][j
]], 1);
173 case 'L': f
.garbleLeft(i
, j
); break;
174 case 'R': f
.garbleRight(i
, j
); break;
180 static int mulModulo(int a
, int b
) {
181 return (int)((long)a
* b
% MODULO
);
184 static int addModulo(int a
, int b
) {
185 return (a
+ b
) % MODULO
;
188 void write() throws Exception
{
189 PrintWriter out
= new PrintWriter("garbling.out");
190 for (int i
= 0; i
< r
* c
; i
++) {
191 out
.println(writtenModulo
[i
]);
196 //----------------- just for validation ------------------
199 * Strict scanner to verify 100% correspondence between input files and input file format specification.
200 * It is a drop-in replacement for {@link java.util.Scanner} that could be added to a soulution source
201 * (cut-and-paste) without breaking its ability to work with {@link java.util.Scanner}.
203 public class Scanner
{
204 private final BufferedReader in
;
205 private String line
= "";
208 private boolean localeset
;
210 public Scanner(File source
) throws FileNotFoundException
{
211 in
= new BufferedReader(new FileReader(source
));
215 public void close() {
216 assert line
== null : "Extra data at the end of file";
219 } catch (IOException e
) {
220 throw new AssertionError("Failed to close with " + e
);
224 public void nextLine() {
225 assert line
!= null : "EOF";
226 assert pos
== line
.length() : "Extra characters on line " + lineNo
;
228 line
= in
.readLine();
229 } catch (IOException e
) {
230 throw new AssertionError("Failed to read line with " + e
);
236 public String
next() {
237 assert line
!= null : "EOF";
238 assert line
.length() > 0 : "Empty line " + lineNo
;
240 assert line
.charAt(0) > ' ' : "Line " + lineNo
+ " starts with whitespace";
242 assert pos
< line
.length() : "Line " + lineNo
+ " is over";
243 assert line
.charAt(pos
) == ' ' : "Wrong whitespace on line " + lineNo
;
245 assert pos
< line
.length() : "Line " + lineNo
+ " is over";
246 assert line
.charAt(0) > ' ' : "Line " + lineNo
+ " has double whitespace";
248 StringBuilder sb
= new StringBuilder();
249 while (pos
< line
.length() && line
.charAt(pos
) > ' ')
250 sb
.append(line
.charAt(pos
++));
251 return sb
.toString();
254 public int nextInt() {
256 assert s
.length() == 1 || s
.charAt(0) != '0' : "Extra leading zero in number " + s
+ " on line " + lineNo
;
257 assert s
.charAt(0) != '+' : "Extra leading '+' in number " + s
+ " on line " + lineNo
;
259 return Integer
.parseInt(s
);
260 } catch (NumberFormatException e
) {
261 throw new AssertionError("Malformed number " + s
+ " on line " + lineNo
);
265 public long nextLong() {
267 assert s
.length() == 1 || s
.charAt(0) != '0' : "Extra leading zero in number " + s
+ " on line " + lineNo
;
268 assert s
.charAt(0) != '+' : "Extra leading '+' in number " + s
+ " on line " + lineNo
;
270 return Long
.parseLong(s
);
271 } catch (NumberFormatException e
) {
272 throw new AssertionError("Malformed number " + s
+ " on line " + lineNo
);
276 public double nextDouble() {
277 assert localeset
: "Locale must be set with useLocale(Locale.US)";
279 assert s
.length() == 1 || s
.startsWith("0.") || s
.charAt(0) != '0' : "Extra leading zero in number " + s
+ " on line " + lineNo
;
280 assert s
.charAt(0) != '+' : "Extra leading '+' in number " + s
+ " on line " + lineNo
;
282 return Double
.parseDouble(s
);
283 } catch (NumberFormatException e
) {
284 throw new AssertionError("Malformed number " + s
+ " on line " + lineNo
);
288 public void useLocale(Locale locale
) {
289 assert locale
== Locale
.US
;