ABC 138 screencast
https://atcoder.jp/contests/abc138/tasks
https://drive.google.com/file/d/15FST30n57Kb4yDPkUfNV4E4XR8qL8XLN/view
Problem C We should use items in ascending order because the first item thrown into the bin is finally multiplied by 1/2**(N-1).
Problem D I think the problem C is more difficult than the problem D.
Problem E We can find subsequence greedily. We just speed up it.
Problem F In binary representation, the number of digits of x and y must be the same. If same, y % x is equivalent to y-x. y-x and x^y is the same if and only if y-x has no borrows. Similar fact appears in recent ABC, which is not subtraction but addition. Therefore, we can solve it using digit DP.
CF 579 Div. 3 F Complete the Projects
I wonder why my solutions passes. My solution is quite different from the official solution. We assume that the optimal solution forms like this. In the following figure, elements are sorted in descending order according to a[i].
+-------+ +-----+ +---------+ v | v | v | +-+-+-+-+-+ +-+-+-+-+ +-+-+-+-+-+-+ |5|1|2|3|4| |4|1|2|3| |6|1|2|3|4|5| +-+-+-+-+-+ +-+-+-+-+ +-+-+-+-+-+-+ | | ^ | ^ +---------------+ +-|------------ ... +-------------+
If this is right, we can solve this problem by the following algorithm. If you find any hack case, you can hack it from https://codeforces.com/contest/1203/submission/58747572.
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); i++) #define repr(i, n) for (int i = (n) - 1; i >= 0; i--) using namespace std; using ll = long long; void chmax(int &x, int y) { x = max(x, y); } int main() { cin.tie(nullptr); ios::sync_with_stdio(false); int n, r; cin >> n >> r; vector<int> a(n), b(n); vector<int> pos, neg; rep(i, n) { cin >> a[i] >> b[i]; if (b[i] >= 0) pos.push_back(i); else neg.push_back(i); } sort(pos.begin(), pos.end(), [&](int i, int j) { return a[i] < a[j]; }); sort(neg.begin(), neg.end(), [&](int i, int j) { return a[i] > a[j]; }); int cnt = 0; for (int i : pos) { if (r < a[i]) continue; r += b[i]; cnt++; } static int dp[101][102][102]; rep(i, 101) rep(j, 102) rep(k, 102) dp[i][j][k] = -1e9; const int m = neg.size(); dp[0][m][0] = r; for (int i = 0; i <= m; i++) { for (int j = 0; j <= m; j++) { for (int k = 0; k <= m; k++) { if (j != m) { if (dp[i][j][k] >= a[neg[j]]) { chmax(dp[i][m][k+1], dp[i][j][k] + b[neg[j]]); } } if (i < m) { chmax(dp[i+1][j][k], dp[i][j][k]); if (dp[i][j][k] >= a[neg[i]]) { chmax(dp[i+1][j][k+1], dp[i][j][k] + b[neg[i]]); } } if (i < m && j == m) { chmax(dp[i+1][i][k], dp[i][j][k]); } } } } repr(i, m+1) { if (dp[m][m][i] >= 0) { cout << i + cnt << endl; return 0; } } }
CF 578 Div 2 E. Compress Words
https://codeforces.com/contest/1200/problem/E
The array used in KMP algorithm is useful to compute the length of common string. Someone may think this algorithm is squared time, but we don't have to treat whole string, so it works in linear time.
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); i++) #define repr(i, n) for (int i = (n) - 1; i >= 0; i--) using namespace std; using ll = long long; vector<int> kmp(string s) { int n = s.size(); vector<int> p(n + 1); p[0] = -1; int j = -1; for (int i = 0; i < n; i++) { while (j != -1 && s[i] != s[j]) j = p[j]; p[i + 1] = ++j; } return p; } int main() { cin.tie(nullptr); ios::sync_with_stdio(false); int n; cin >> n; string ans; rep(i, n) { string s; cin >> s; string tmp = ans.substr(max(0, (int)ans.size() - (int)s.size())); ans += s.substr(kmp(s + "$" + tmp).back()); } cout << ans << endl; }
ABC 137 screencast
Problem C: I forget a hashtable whenever I use C++. C++'s hashtable is really dangerous because it doesn't use randomness.
Problem D: Considering reversed time, the items we can choose increases. Therefore, we can solve it greediliy.
Problem E: Since the problem statements says you should use Bellman-Ford, I solved it speedily. However, I mistook the way to detect positive cycles. I thought by 2N iterations the effect of positive cycles propagates to the terminal.
Problem F: Just use Lagrange's interpolation. It is difficult for me to implement division and Lagrange's interpolation. Both of them are rarely appears in contests, so that is natural. But I hope to implement them more rapidly.
ABC 136 F. Enclosed Points
https://atcoder.jp/contests/abc136/tasks/abc136_f
I solved problems with F# because I don't want to use C++. Although I prefer to OCaml, I gave up it due to 64bit integers. I use verbose F# because in off-side rule we can't restore indents when carelessly erase them. OCaml is almost as fast as C++, where F# is a little slow regarding IO, so we should prepare own IO functions. Unbuffered IO is really slow.
UPD: I thought F# is available in Codeforces, but it is unavailable now. OCaml is not suitable for contest because OCaml doesn't have binary operators for 64bit integers. In 64bit platform, int has 64 bit precision, but Codeforces is now 32bit.
UPD: The following source code realize Int64 arithmetics. I want to use https://caml.inria.fr/pub/docs/manual-ocaml/manual042.html, but no contests support now. I want to replace all int with Int64, but some functions in the standard library takes int, so I can't.
open Scanf open Printf module L = struct open Int64 let ( + ), ( - ), ( * ), ( / ), ( % ), ( ~- ) = add, sub, mul, div, rem, neg end let ( ~~ ) = Int64.of_int let ( !! ) = Int64.to_int let readint () = scanf " %d" (fun x -> x) let readint64 () = scanf " %Ld" (fun x -> x) module M = struct let md = 7L let ( + ) x y = let z = Int64.add x y in if z < md then z else Int64.sub z md let ( - ) x y = let z = Int64.sub x y in if z >= 0L then z else Int64.add z md let ( * ) x y = Int64.rem (Int64.mul x y) md end type bit = { dat : int64 array } module BIT = struct let make (n : int) : bit = { dat=Array.make (n + 1) 0L } let update (bit : bit) (k : int) (v : int64) = let { dat } = bit in let i = ref (k + 1) in while !i < Array.length dat do dat.(!i) <- L.(dat.(!i) + v); i := !i + (!i land -(!i)) done let query (bit : bit) (k : int) : int64 = let { dat } = bit in let i = ref k in let ans = ref 0L in while !i > 0 do ans := L.(!ans + dat.(!i)); i := !i - (!i land -(!i)) done; !ans end let () = assert (L.(2L + 3L) = 5L); assert (L.(2L - 3L) = -1L); assert (L.(2L * 3L) = 6L); assert (L.(2L / 3L) = 0L); assert (L.(2L % 3L) = 2L); assert (L.(min 2L 3L) = 2L); assert (M.(4L + 5L) = 2L); assert (M.(4L - 5L) = 6L); assert (M.(4L * 5L) = 6L); let bit = BIT.make 10 in for i = 0 to 9 do BIT.update bit i ~~(i+1) done; for i = 0 to 10 do let i = ~~i in assert (BIT.query bit !!i = L.(i * (i + 1L) / 2L)) done; try (BIT.query bit (-1) |> ignore; failwith "") with _ -> (); try (BIT.query bit 11 |> ignore; failwith "") with _ -> ();
I used the following template. I'll omit the template.
#nowarn "62" #light "off" open System;; open System.IO;; let reader = new StreamReader(new BufferedStream(Console.OpenStandardInput ()));; let writer = new StreamWriter(new BufferedStream(Console.OpenStandardOutput ()));; let skipSpaces () = while reader.Peek () <= int ' ' do reader.Read () |> ignore done;; let read f = skipSpaces (); [|while reader.Peek () > int ' ' do yield char (reader.Read ()) done |] |> System.String |> f;; let readint () = skipSpaces (); let s = if reader.Peek() = int '-' then (ignore (reader.Read()); -1) else 1 in let mutable ans = 0 in while reader.Peek () > int ' ' do ans <- ans * 10 + (reader.Read () - int '0'); done; s * ans;; let write (s : string) = writer.Write s;; let writeln (s : string) = writer.WriteLine s;; (* Write code here *) reader.Close();; writer.Close();;
Problem A
let a, b, c = readint (), readint (), readint();; c - min (a - b) c |> printfn "%d";;
Problem B
I wrote keta function. string >> String.length
may be simpler than it.
let rec keta n = if n = 0 then 0 else 1 + keta (n / 10);; let N = readint ();; {1..N} |> Seq.filter (fun x -> keta x % 2 = 1) |> Seq.length |> printfn "%d";
Problem C
As looking at elements from left to right, greedily subtract one from each element if we can.
A.[0] <- A.[0] - 1;; let mutable ans = true;; for i in 1..N-1 do if A.[i-1] > A.[i] then ans <- false elif A.[i-1] < A.[i] then A.[i] <- A.[i] - 1 done;; (if ans then "Yes" else "No") |> printfn "%s";;
Problem D
It seems that doubling solution is easy to write than I thought. I wrote two pointers.
let S = read string;; let N = S.Length;; let mutable i = 0;; let ans = Array.create N 0;; while i < N do let j = i in i <- {i..N} |> Seq.find (fun i -> i = N || S.[i] <> 'R'); let k = i in i <- {i..N} |> Seq.find (fun i -> i = N || S.[i] <> 'L'); let a, b = k - j, i - k in ans.[k-1] <- ((a + 1) / 2 + b / 2); ans.[k] <- (a / 2 + (b + 1) / 2); done;; ans |> Array.map string |> String.concat " " |> writeln;;
Problem E
Once we notice that the sum doesn't change, we almost have solved this problem. That's a lie. Greedy part is not trivial for me.
let divisors x = Seq.initInfinite ((+) 1) |> Seq.takeWhile (fun i -> i * i <= x) |> Seq.filter (fun i -> x % i = 0) |> Seq.collect (fun i -> seq [i; x / i]);; let N, K = readint (), readint ();; let A = Array.init N (ignore >> readint);; let f d = let x = Array.init N (fun i -> A.[i] % d) |> Array.sort in let mutable i = 0 in let mutable j = N - 1 in let mutable souwa = 0 in while i < j do let tukau = min x.[i] (d - x.[j]) in souwa <- souwa + tukau; x.[i] <- x.[i] - tukau; x.[j] <- x.[j] + tukau; if x.[i] = 0 then i <- i + 1; if x.[j] = d then j <- j - 1; done; souwa <= K;; divisors (Array.sum A) |> Seq.filter f |> Seq.max |> printf "%d";;
Problem F
If we can notice that x[i]!=x[j] and y[i]!=y[j], this problem become a little easier. However, we can solve this problem without this constraint (My first solution is so).
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
is too long.
let MOD = 998244353;; type Mint = Mint of int with static member (+) (Mint x, Mint y) = Mint (let z = x + y in if z < MOD then z else z - MOD) static member (-) (Mint x, Mint y) = Mint (let z = x - y in if z >= 0 then z else z + MOD) static member (*) (Mint x, Mint y) = int64 x * int64 y % int64 MOD |> int |> Mint override this.ToString() = match this with Mint x -> x.ToString() end;; type BIT = { dat : int [] } [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module BIT = begin let create n : BIT = { dat = Array.create (n + 1) 0 } let update ({dat=dat} : BIT) (k : int) (v : int) = let mutable i = k + 1 in while i < Array.length dat do dat.[i] <- dat.[i] + v; i <- i + (i &&& -i) done let query ({dat=dat} : BIT) (k : int) : int = let mutable i = k in let mutable ans = 0 in while i > 0 do ans <- ans + dat.[i]; i <- i - (i &&& -i) done; ans end;; let N = readint ();; let X, Y = Array.init N (fun _ -> readint (), readint ()) |> Array.sort |> Array.unzip;; let YD = Y |> Array.distinct |> Array.sort |> Array.mapi (fun i x -> x, i) |> Map.ofArray;; for i in 0..N-1 do Y.[i] <- YD.[Y.[i]] done;; let L = BIT.create YD.Count;; let R = BIT.create YD.Count;; for y in Y do BIT.update R y 1 done;; let two = Array.replicate N (Mint 2) |> Array.scan (*) (Mint 1);; let mutable ans = two.[N] * (Mint N);; for i in 0..N-1 do BIT.update R Y.[i] (-1); let d = BIT.query L Y.[i] in let c = BIT.query R Y.[i] in let a = i - d in let b = (N-1-i-c) in [Mint 1; two.[a] - Mint 1; two.[b] - Mint 1; two.[c] - Mint 1; two.[d] - Mint 1; (two.[a] - Mint 1) * (two.[b] - Mint 1); (two.[b] - Mint 1) * (two.[c] - Mint 1); (two.[c] - Mint 1) * (two.[d] - Mint 1); (two.[d] - Mint 1) * (two.[a] - Mint 1)] |> List.iter (fun x -> ans <- ans - x); BIT.update L Y.[i] 1; done;; printfn "%O" ans;;