Quantcast
Channel: CodeChef Discuss - latest questions
Viewing all 40121 articles
Browse latest View live

AMR15E - Editorial

$
0
0

PROBLEM LINK

Practice
Contest

Panel Members

Problem Setter:Suhash
Problem Tester:
Editorialist:Sunny Aggarwal
Contest Admin:
Russian Translator:
Mandarin Translator:
Vietnamese Translator:
Language Verifier:

DIFFICULTY:

Medium-Hard

PREREQUISITES:

Offline processing, Mo's Algorithm, Binary Indexed Tree, Segment Tree, Mathematics.

PROBLEM:

Given an array consisting of $N$ elements each having value $A_i <= 10^9$. We are asked to process $M$ queries on array $A$ where each query consists of two integers $L$ and $R$ indicating a sub segment and asked to compute following expression on the given segment.

$$Required Answer = \sum_{\substack{S_i \in S}}{S_i * i}$$

Where $S$ denotes the sorted list of unique elements in the range $L$ to $R$ and $i$ denotes the index of $S_i^{th}$ element in list $S$. ( 1 based indexing is used )

EXPLANATION

Given problem has offline solution i.e we will store all the queries at first and will answer them all together in the end.

Sort all the queries using Mo's algorithm. If you are not familiar with the Mo's Algorithm. Please go through this blog or this blog first.

For the purpose of simplicity, Apply coordinate compression on the values of given array $A$ i.e map them in the range $[1, N]$ and also maintain a mapping of new values with the old values. Look at the following code for better understanding of mapping.

void solve() {
    int n;
    cin >> n;
    map<int, int=""> M; // stl map
    for(int i=1; i<=n; i++) {
        cin >> A[i];
        M[A[i]] = 0;
    }
    int newval = 0;
    for(auto &it: M) {it.sd = ++ newval; // assigning new value and maintaining mapping
    }
}
// note that M[x] stores the new value of element x.

We are required to maintain following data structures to solve this problem efficiently.

  • An array say $F[]$ that stores the frequency of each element present in the considered range.
  • A Segment tree / Binary Indexed Tree for the fast update and query sum say $S$.
  • A Segment tree / Binary Indexed Tree for the fast update and query count say $C$.
  • Let us assume that variable $ans$ denotes the answer of current query.

Initially ans is initialised to 0. We will consider all queries one by one in new order and update the current $ans$ for the new query.

Only $Add$ and $Remove$ function used in Mo's algorithm is important here. We will be looking at both one by one.

ADD Function:

Lets see what will happen when we add an element ( say $x$ ) to the current query to answer new query.

Case 1: Either the added element $x$ already exist in the previous query. If Yes, then we don't need to worry about anything as it won't affect our answer but we will update our frequency array $F[]$ by incrementing count at index $x$ ( note that $x$ is new mapped value of original element and therefore it is in the range $[1, N]$ and we cam simply store frequency by keeping an array of size $N$ ).

Case 2: Or the added element $x$ is not present in the range then we need to update the current answer but how ?

Assume that $1$, $4$, $5$, $7$, $10$ are the $5$ elements that were present in the last query and we have a new element say $x = 6$ in the current query added to it.

We can say that previous answer was $1 * 1 + 2 * 4 + 3 * 5 + 4 * 7 + 5 * 10$.

and new answer will be $1 * 1 + 2 * 4 + 3 * 5 + 4 * 6 + 5 * 7 + 6 * 10$.

We can generalise this change as follows:

new answer = previous answer + ( number of element $ \lt x$ in the previous query + 1 ) * x + ( sum of all elements $\gt x$ in the previous query )

To find the number of elements $\lt x$, we have maintained a count Binary Indexed Tree $C$ and to find the sum of elements having value $\gt x$, we have maintained a sum Binary Indexed Tree $S$.

Above idea can be better understood with the help of following code:

void add(int position) {
    F[M[A[position]]] ++;
    if( F[M[A[position]]] == 1 ) {
        cbit->Update(M[A[position]], 1);
        sbit->Update(M[A[position]], A[position]);
        ans += cbit->RangeQuery(1, M[A[position]]) * A[position];
        ans += sbit->RangeQuery(M[A[position]]+1, n);
    }
}

Remove Function Remove function is analogous to our add function but is exactly opposite. Please have a look at following function to understand it.

void remove(int position) {
    F[M[A[position]]] --;
    if( F[M[A[position]]] == 0 ) {
        ans -= cbit->RangeQuery(1, M[A[position]]) * A[position];
        cbit->Update(M[A[position]], -1);
        sbit->Update(M[A[position]], -A[position]);
        ans -= sbit->RangeQuery(M[A[position]]+1, n);
    }
}

Please refer editorialist's solution for implementation detail and to understand above solution better.

SIMILIAR PROBLEMS

Estimating Progress

Chef and Problems

Chef and Graph Queries

Tree and Queries

Sherlock and Inversions

COMPLEXITY

$O(T*(N+M)*\sqrt(N)\log(N))$


What if I don't get a good answer?

$
0
0

I strive hard to ask a question, but I don’t any satisfactory answer for it. Can you please explain what should I do to get a good answer?

CNOTE - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Sunny Aggarwal
Tester:Hiroto Sekido
Editorialist:Kevin Atienza

DIFFICULTY:

CAKEWALK

PREREQUISITES:

Basic programming

PROBLEM:

Chef has a poem that fits in X pages, but his notebook has only Y pages. So he wants to buy another notebook so that he can finish writing the poem. There are N notebooks for sale and the ith notebook has Pi pages and costs Ci rubles. Chef only has K rubles to spend.

Is it possible for Chef to finish writing his poem?

EXPLANATION:

You simply need to check each notebook if its price is not greater than K and it has at least X - Y pages (because we need X pages but we already have Y pages, we need X - Y more pages). That being said, many contestants still got it wrong, so we'll describe here some common mistakes, and a few suggestions on how to debug and prevent these mistakes from happening in the future.

First, we include implementations in three popular programming contest languages.

C++ code

#include <iostream>
using namespace std;
// allocate more than necessary
int P[111111];
int C[111111];
int main() {
    int T;
    cin >> T;
    for (int cas = 1; cas <= T; cas++) {
        // we use 'cas' because 'case' is a keyword
        int X, Y, K, N;
        cin >> X >> Y >> K >> N;
        bool found = false;
        for (int i = 0; i < N; i++) {
            cin >> P[i] >> C[i];
        }
        for (int i = 0; i < N; i++) {
            if (P[i] >= X - Y && C[i] <= K) {
                found = true;
                break;
            }
        }
        cout << (found ? "LuckyChef" : "UnluckyChef") << '\n';
    }
}

Note that we used '\n' instead of endl, because endl forces a flush, which is unnecessary in our case and significantly slows down our program, causing TLE in the second subtask.

Actually, there is no need to collect books in an array, because we can process each notebook on the fly. thus we can also do the following:

#include <stdio.h>
int main() {
    int T;
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        int X, Y, K, N;
        scanf("%d%d%d%d", &X, &Y, &K, &N);
        bool found = false;
        for (int i = 0; i < N; i++) {
            int P, C;
            scanf("%d%d", &P, &C);
            if (P >= X - Y && C <= K) {
                found = true;
            }
        }
        printf(found ? "LuckyChef\n" : "UnluckyChef\n");
    }
}

We use C-style I/O here (printf/scanf) just to illustrate. Also, note that we removed the "break" statement because we need to finish taking all input lines.

Java code

import java.util.Scanner;
public class Main {
    public static void main(String args[]) throws Exception {
        // "throws Exception" is not recommended in real life, but is
        // very convenient in algorithmic contests!
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int cas = 1; cas <= T; cas++) {
            int X = sc.nextInt();
            int Y = sc.nextInt();
            int K = sc.nextInt();
            int N = sc.nextInt();
            boolean found = false;
            for (int i = 0; i < N; i++) {
                int P = sc.nextInt();
                int C = sc.nextInt();
                if (P >= X - Y && C <= K) {
                    found = true;
                }
            }
            System.out.println(found ? "LuckyChef" : "UnluckyChef");
        }
    }
}

Note that java.util.Scanner provides an easy way to tokenize and read the input. However, for problems with huge inputs and strict time limits (such as the current problem!), it is not recommended because it is slow. Instead, one should use BufferedReader, like so:

import java.io.*;
public class Main {
    public static void main(String args[]) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        for (int cas = 1; cas <= T; cas++) {
            String[] parts = br.readLine().trim().split("\\s+"); // split on whitespace
            int X = Integer.parseInt(parts[0]);
            int Y = Integer.parseInt(parts[1]);
            int K = Integer.parseInt(parts[2]);
            int N = Integer.parseInt(parts[3]);
            boolean found = false;
            for (int i = 0; i < N; i++) {
                parts = br.readLine().trim().split("\\s+");
                int P = Integer.parseInt(parts[0]);
                int C = Integer.parseInt(parts[1]);
                if (P >= X - Y && C <= K) {
                    found = true;
                }
            }
            System.out.println(found ? "LuckyChef" : "UnluckyChef");
        }
    }
}

Python code

T = input()
for cas in xrange(1,T+1):
    X, Y, K, N = map(int, raw_input().strip().split())
    books = []
    for i in xrange(N):
        P, C = map(int, raw_input().strip().split())
        books.append((P, C))
    for P, C in books:
        if P >= X - Y and C <= K:
            print "LuckyChef"
            break
    else:
        print "UnluckyChef"

Note that the python code has a bit of different flavor, specifically the for..else statement. The advantage of it is that there is no more need for a found flag. However, we now have to collect the data in a list.

Common mistakes

Here we list down common mistakes made by the contestants. Note that many of these mistakes apply to most other problems too, and although they are made more frequently by newbies, they occasionally are made by veterans too.

  • Writing out the if condition incorrectly. Here are a few examples (they are all wrong!):

    • P > X - Y && C <= K
    • P >= X - Y && C < K
    • P >= X - Y || C <= K
    • P >= X + Y && C <= K
    • P >= Y - X && C <= K
    • P - Y >= X && C <= K
  • Failing to reinitialize some variables. for example, if you have a flag saying that you found a notebook, then failing to initialize it back to false will most likely mean "WA". For example, the ff is wrong:

    import java.io.*;
    public class Main {
        public static void main(String args[]) throws Exception {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int T = Integer.parseInt(br.readLine());
            boolean found = false;
            for (int cas = 1; cas <= T; cas++) {
                String[] parts = br.readLine().trim().split("\s+");
                int X = Integer.parseInt(parts[0]);
                int Y = Integer.parseInt(parts[1]);
                int K = Integer.parseInt(parts[2]);
                int N = Integer.parseInt(parts[3]);
                for (int i = 0; i < N; i++) {
                    parts = br.readLine().trim().split("\s+");
                    int P = Integer.parseInt(parts[0]);
                    int C = Integer.parseInt(parts[1]);
                    if (P >= X - Y && C <= K) {
                        found = true;
                    }
                }
                System.out.println(found ? "LuckyChef" : "UnluckyChef");
            }
        }
    }

Note that the found variable is not reinitialized to false for every test case, which means that when it prints LuckyChef once, it will continue doing so for all subsequent cases. This even fails the sample input!

  • Breaking out of the loop early, without collecting all the input lines. Take a look at the following code:
    #include <iostream>
    using namespace std;
    int P[100000];
    int C[100000];
    int main() {
        int T;
        cin >> T;
        for (int cas = 1; cas <= T; cas++) {
            int X, Y, K, N;
            cin >> X >> Y >> K >> N;
            bool found = false;
            for (int i = 0; i < N; i++) {
                cin >> P[i] >> C[i];
                if (P[i] >= X - Y && C[i] <= K) {
                    found = true;
                    break;
                }
            }
            cout << (found ? "LuckyChef" : "UnluckyChef") << '\n';
        }
    }

The problem with this code is that if you found a good notebook early on, it immediately breaks out of the loop, failing to read all (Pi, Ci) pairs. So it fails to read the next case properly, possibly causing TLE/WA/RE verdicts, depending on how the next few numbers are interpreted.

  • Not following the output format exactly. Many things can go wrong here:

    • Failing to print newlines, e.g. in C++, wrongly using printf("LuckyChef") instead of printf("LuckyChef\n") (or puts("LuckyChef")), and in Java, wrongly using System.out.print instead of System.out.println.
    • Wrong capitalization: printf("luckyChef\n")
    • Printing extra characters: printf("LuckyChef!\n"). This includes printing extra spaces, such as printf("Lucky Chef\n"), printf(" LuckyChef\n"), printf("LuckyChef \n"), which is normally not tolerated (note that some judges accept trailing spaces/new lines, but it won't hurt to be really careful!). Also, don't do printf("\nLuckyChef")!
    • Printing a blank line anywhere, e.g. in between inputs, or at the end.

The lesson is simply to be really careful about what you're printing. Also, there is a common mistake regarding new lines at the end of file. Normally, a "line" is terminated by a new line character '\n', including the last line. Some contestants intentionally omit the new line character at the last test case, which obfuscates/complicates the program a bit, and depending on the judge also incurs WA/PE. So when the problem says "print a line containing..." or "print ... in a line", always ensure that a trailing new line character '\n' is printed (certain print functions in some languages automatically does so, for example System.out.println).

  • Failing to allocate a large-enough array. For example, only allocating 10000 instead of 100000 by accident. This also includes some off-by-one errors if one uses 1-based indexing, such as in the following:
    
    import java.io.*;
    public class Main {
        public static void main(String args[]) throws Exception {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int T = Integer.parseInt(br.readLine());
            int P[] = new int[100000];
            int C[] = new int[100000];
            for (int cas = 1; cas <= T; cas++) {
                String[] parts = br.readLine().trim().split("\s+"); // split on whitespace
                int X = Integer.parseInt(parts[0]);
                int Y = Integer.parseInt(parts[1]);
                int K = Integer.parseInt(parts[2]);
                int N = Integer.parseInt(parts[3]);
                boolean found = false;
                for (int i = 1; i <= N; i++) {
                    parts = br.readLine().trim().split("\s+");
                    P[i] = Integer.parseInt(parts[0]);
                    C[i] = Integer.parseInt(parts[1]);
                }
                for (int i = 1; i <= N; i++) {
                    if (P[i] >= X - Y && C[i] <= K) {
                        found = true;
                        break;
                    }
                }
                System.out.println(found ? "LuckyChef" : "UnluckyChef");
            }
        }
    }
    This will run correctly in most inputs, but when N = 100000, this will give runtime error.

The lesson here is to learn to use 0-based indexing. It's also a good idea to allocate more than is needed, just to guard against these types of errors (see also defensive programming), for an example, see the first C++ code above. It's also a good idea to allocate the array as needed:

import java.io.*;
public class Main {
    public static void main(String args[]) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        for (int cas = 1; cas <= T; cas++) {
            String[] parts = br.readLine().trim().split("\\s+"); // split on whitespace
            int X = Integer.parseInt(parts[0]);
            int Y = Integer.parseInt(parts[1]);
            int K = Integer.parseInt(parts[2]);
            int N = Integer.parseInt(parts[3]);
            // allocate only when needed
            // we're relying on the garbage collector to deallocate this.
            // some languages don't have garbage collection, so you need
            // to deallocate this manually if you don't want to waste memory.
            int P[] = new int[N];
            int C[] = new int[N];
            boolean found = false;
            for (int i = 0; i < N; i++) {
                parts = br.readLine().trim().split("\\s+");
                P[i] = Integer.parseInt(parts[0]);
                C[i] = Integer.parseInt(parts[1]);
            }
            for (int i = 0; i < N; i++) {
                if (P[i] >= X - Y && C[i] <= K) {
                    found = true;
                    break;
                }
            }
            System.out.println(found ? "LuckyChef" : "UnluckyChef");
        }
    }
}

(note however that this doesn't pass the time limit, so better use other techniques)

...or simply use structures that resize naturally, like the Python example above.

  • Taking input from a file/writing into a file! The input should be taken from the standard input (stdin) and the output should be written in the standard output (stdout).

  • Mistakenly using the same loop index in nested loops, e.g.

    #include <stdio.h>
    int main() {
        int T, i;
        scanf("%d", &T);
        for (i = 1; i <= T; i++) {
            int X, Y, K, N;
            scanf("%d%d%d%d", &X, &Y, &K, &N);
            bool found = false;
            for (i = 0; i < N; i++) {
                int P, C;
                scanf("%d%d", &P, &C);
                if (P >= X - Y && C <= K) {
                    found = true;
                }
            }
            printf(found ? "LuckyChef\n" : "UnluckyChef\n");
        }
    }
    Try running this program on the sample input and see what happens!

The lesson is to use different loop variables. Also, as a precaution, it is a good idea to declare the variable in the loop initializer itself, because some compilers can detect accidental reuse of loop indices.

Suggestions

Now that you've learned that many, many things can go wrong even for such a simple problem, how does one go about preventing it?

Well, for one, it is usually hard to write a completely correct code in the first try. Therefore one should always test the code before submitting it! For example, use the sample data. The sample data is provided for two reasons:

  • To ensure that you are following the input/output format correctly, and
  • To ensure that you at least get some small inputs correctly.

However, if you pass the sample input, it doesn't mean you'll pass the actual input! So it still lies upon the contestant to ensure that their program will pass whatever kind of test case the judge can give to it. So if the judge returns WA, try making some inputs yourself, until you find one where your program fails. Then start debugging from there. In other problems, it is sometimes useful to make random input generators.

Also, there is the occasional problem that tests how well you follow instructions and handle many tricky edge cases. In such problems, speed/minute optimizations are secondary to correctness, so things like readability/modularity more important, at the expense of efficiency. See the sample programs above as examples, which were written partly with readability in mind.

Time Complexity:

$O(N)$

AUTHOR'S AND TESTER'S SOLUTIONS:

Setter
Tester

DEVCLASS - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Praveen Dhinwa
Tester:Hiroto Sekido
Editorialist:Kevin Atienza

DIFFICULTY:

EASY

PREREQUISITES:

Ad hoc, string processing, greedy

PROBLEM:

Given a string s of length n consisting of letters B and G, and an integer called type (which can only be 0, 1 or 2). You need to rearrange the letters so that no two adjacent positions contain the same letter. The only valid moves are swaps between two positions, and the cost of swapping positions i and j is equal to $|i-j|$type.

QUICK EXPLANATION:

  • There are only two strings with no adjacent same letters, so we try each string t and check if it is possible to transform s to t.

  • We solve the problem differently for each value of type.

  • When type = 0, the cost of swapping numbers is always 1. The answer is simply the number of positions where s and t differ, divided by two.

  • It is never beneficial to swap to positions containing the same letter. Thus the relative ordering of the Gs and Bs will stay the same, and one can easily compute the final position of each letter.

  • When type = 1, one can show that there is always a solution involving only swaps of adjacent elements. From this, one can show that the answer is just the sum of the distances of each letter to its final position, divided by two.

  • When type = 2 (and also, when type> 2), one can also show that the answer is the same as for type = 1.

EXPLANATION:

Throughout this explanation, we will use zero-based indexing, so the first letter of s is s0, and the last is sn-1.

Let's call a string likable if no two adjacent positions contain the same letter. Notice that there are only two likable strings of length n: one starting with G (GBGBGB...) and one starting with B (BGBGBG...).

We are only rearranging the letters in s, so the number of Gs and Bs will not change. This means that if the number of Gs and Bs do not match any of the likable strings above, then we immediately know that the task is impossible, so we can already output -1. On the other hand, if the numbers match at least one likable string t, then it's always possible to rearrange s into t, because any permutation can be decomposed into a series of swaps. So the answer in the latter case is the minimum cost of rearranging from s to any likable string t. There are only two t's to check, so in what follows, we fix the likable string t.

We have reduced the problem into finding the minimum cost of rearranging s into t. Notice that the cost is dependent on type, and the cost function for each type are somewhat different from one another, so we will need to make a separate solution for each of the possible values of type. We start with type = 0.

Making a string likable, when type = 0

If type = 0, then the cost of swapping positions i and j is equal to $|i-j|$0, or simply 1. This means that we are simply trying to minimize the number of swaps needed to transform s into t :)

A greedy algorithm can be used for this purpose. Let D be the number of positions where s and t differ. Then s and t are equal if and only if D = 0. But there are a couple more observations:

  • D is the number of positions i such that either (1) si = G and ti = B, or (2) si = B and ti = G. But s and t have the same number of Gs and Bs, so the number of positions that satisfy (1) must be equal to the number of positions that satisfy (2) (why?). It follows that D is even.
  • Notice that whenever we swap two elements in the string, we can only reduce D by at most 2. Therefore, the minimum number of swaps is at least D/2.
  • On the other hand, it is always possible to transform s into t in D/2 steps: Select a position i that satisfies (1) and a position j that satisfies (2), and swap si and sj. This reduces D by two, so one can repeat this process D/2 times and D will become zero.

These observations simply say that the answer is half the number of positions where s and t differ! Thus, this can be computed in $O(n)$ time with a simple loop, and a single division at the end. The following pseudocode illustrates this:

def min_cost_type_0(s, t):
    ans = 0
    for i from 0 to n - 1
        if s[i] != t[i]
            ans += 1

    return ans / 2

It is easy to see that this runs in $O(n)$ time.

Making a string likable, when type = 1

Next, let's move on to the case where type = 1. This time, the cost of swapping positions i and j is $|i-j|$1 = $|i-j|$, or simply the distance between the positions i and j.

First, note that we can simulate any swap of cost 2 with two swaps of cost 1. For example, suppose we want to swap positions 1 and 3 in the string BBG (which yields GBB). Then we can instead swap positions 2 and 3 to get BGB, and then positions 1 and 2 to get GBB. If instead the string was BGG, then we can swap positions 1 and 2, and then 2 and 3, to get the desired GGB. Similar replacements can be done for strings GBB and GGB. Therefore, we don't have to consider swaps of cost 2 anymore.

In fact, we can extend the above argument to show how to simulate any swap of cost k with k swaps of cost 1! For example, suppose we want to swap positions 1 and k+1 in the string B???????G (let's say the B is in position 1 and the G is in position k+1, and we don't know about the values of the ?s). Also, suppose that we have already shown that swaps of costs k'< k can be replaced with k' swaps of cost 1 (induction). We then handle two cases, depending on the letter on position k (second-to-last letter):

  • If the letter on position k is a B, then we want to transform B??????BG to G??????BB. One can first swap positions k and k+1 to get B??????GB, and then swap positions 1 and k to get the desired G??????BB. The following illustrates it:

    B??????BG || B??????GB | | G??????BB

However, the second swap only costs k-1, so we can replace it with k-1 swaps of cost 1. The result is k swaps of cost 1 which performs exactly what we want.

  • If the letter on position k is a G, then we want to transform B??????GG to G??????GB. One can first swap positions 1 and k to get G??????BG, and then swap positions 1 and k to get the desired G??????GB. The following illustrates it:

    B??????GG | | G??????BG || G??????GB

Once again, we replace the first swap with swaps of cost 1 because it only costs k-1.

The case G???????B can be handled similarly. Thus, it is always possible to replace any valid solution by a series of adjacent swaps (swaps of adjacent elements) without increasing the cost, so we may simply restrict ourselves to swaps of cost 1.

Using only adjacent swaps

We now wish to find the minimum number of swaps needed to transform s to t, if only adjacent swaps are allowed. Let's only handle the case where t starts with a G (the other case is essentially the same).

The first observation is that it is never beneficial to swap two positions if they contain the same element. Thus, the relative orders of all the Bs with each other will stay the same throughout. The same is true for the Gs. This means the following:

  • we already know where each letter will end up in the final array: the i'th B ($i \ge 0$) in s will end up at position $2i+1$ in t and the i'th G in s will end up at position $2i$ in t . Let's denote by $f_j$ the final position of sj.
  • we also know how many steps at the minimum each letter will move: since sj will end up at position $f_j$, it has to travel at least $|f_j - j|$ steps. Let's denote by $M_j$ the quantity $f_j - j$ (without the absolute value), so $M_j$ also encodes which direction sj needs to go (e.g. negative for "left").
  • each swap moves exactly two elements, so the total number of steps each number will move is equal to twice the number of swaps.

Thus, the answer is at least half of the sum $|M_0| + |M_1| + \cdots + |M_{n-1}|$. But can it always be done with exactly this number of steps? The answer is yes! To show this, we only need to show that if s $\not=$ t, then there exists adjacent positions i and i+1 such that $M_i > 0$ and $M_{i+1} < 0$, so we can swap them and reduce the sum above by two.

To show it, let j be the first position where s and t differ. Suppose that sj is a G (the other case can be handled similarly). Also, let sk be the first B after sj. Note that $M_0, M_1, \ldots, M_{j-1}$ are all zero, but $M_j$ is not. We also have the following observations:

  • $M_k < 0$, because sk's final position is j (Actually we have $M_k = j - k$).
  • $M_j, M_{j+1}, M_{j+2}, \ldots, M_{k-1}$ are all $> 0$. This is because they are all Gs, so they will have to eventually end up to the right of the B in position k, so they have to move at least one step right.

In particular, $M_{k-1} > 0$ and $M_k < 0$, which is exactly what we want! Therefore, the answer is exactly half the value $|M_0| + |M_1| + \cdots + |M_{n-1}|$.

The following pseudocode illustrates this (note that we have removed the assumption that t starts with a G):

def min_cost_type_1(s, t):
    ans = 0
    count_eq = 0 // how many letters encountered equal t[0]?
    count_ne = 0 // how many letters encountered don't equal t[0]?
    for i from 0 to n - 1
        if s[i] == t[0]
            ans += abs(i - (2*count_eq))
            count_eq += 1
        else
            ans += abs(i - (2*count_ne+1))
            count_ne += 1

    return ans / 2

This also clearly runs in $O(n)$.

Making a string likable, when type = 2

Finally, we handle the case where type = 2. Similarly to the type = 1 case, we can also replace a swap of distance d with dadjacent swaps. But this one is even better: the cost of swapping with distance d is d2, while simulating it with d adjacent swaps requires only a cost of d. Thus, we are better off only swapping adjacent elements, and so the solution is the same as for type = 1! So no additional work is needed: the min_cost_type_1 function above works also for type = 2 (and indeed for any type> 2!).

Code

Let's summarize what we discussed above in pseudocode:

// solve the test case (s, type)
def solve_case(s, type):
    result = min(t_solve_case(s, type, 'G'), t_solve_case(s, type, 'B'))
    if result < infinity
        return result
    else
        return -1

// solve the test case (s, type), assuming the target 't' starts with letter 't_start'
def t_solve_case(s, type, t_start):
    n = s.length
    if t_start == "B"
        t = "BGBGBGBG..." // of length n
    else
        t = "GBGBGBGB..." // of length n

    if count_occurrences(n, s, 'G') != count_occurrences(n, t, 'G') // no need to check for 'B'
        return infinity

    if type == 0
        return min_cost_type_0(n, s, t)
    else
        return min_cost_type_1(n, s, t)

// how many times the letter 'c' appears in string 's'
def count_occurrences(n, s, c):
    count = 0
    for i from 0 to n - 1
        if s[i] == c
            count += 1
    return count

def min_cost_type_0(n, s, t):
    ans = 0
    for i from 0 to n - 1
        if s[i] != t[i]
            ans += 1

    return ans / 2

def min_cost_type_1(n, s, t):
    ans = 0
    count_eq = 0
    count_ne = 0
    for i from 0 to n - 1
        if s[i] == t[0]
            ans += abs(i - (2*count_eq))
            count_eq += 1
        else
            ans += abs(i - (2*count_ne+1))
            count_ne += 1

    return ans / 2

Author's solution for type $\ge$ 1

Here we describe the author's solution to the case type = 1 (and thus will also apply for type> 1). It's a bit different (and nicer!) from the solution described above, but I chose it because in my opinion its correctness is easier to show.

First, we create an array a[0..n-1], defined as follows:

  • a[i] = 0, if si $=$ ti.
  • a[i] = 1, if si $\not=$ ti and si = B and ti = G.
  • a[i] = -1, if si $\not=$ ti and si = G and ti = B.

Now in this problem, you have to move elements here and there in such a way that finally all the elements of the array becomes zero and the total operations taken is minimized. Formally, you have to match 1's with -1's so that the sum of the distances between matched pairs is minimized. This problem is a simplified version of problem PRLADDU.

The solution now is very easy and can be described by the following pseudocode:

def min_cost_type_1(s, t):
    ans = 0
    curr = 0
    for i from 0 to n - 1
        curr += a[i]
        ans += abs(curr)

    return ans

The proof of this is given in the editorial of the problem. Also the editorial gives a quite nice detailed proof of this strategy.

Time Complexity:

$O(n)$

AUTHOR'S AND TESTER'S SOLUTIONS:

setter
tester

STRSUB - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Lalit Kundu
Tester:Hiroto Sekido
Editorialist:Kevin Atienza

DIFFICULTY:

SIMPLE

PREREQUISITES:

Dynamic programming, preprocessing, binary search, cumulative sums

PROBLEM:

You are given a string $S$ of length $N$ consisting only of $0$s and $1$s. You are also given an integer $K$.

You have to answer $Q$ queries. In the $i$th query, two integers $L$ and $R$ are given. Then you should print the number of substrings of $S[L, R]$ which contain at most $K$ $0$s and at most $K$ $1$s where $S[L, R]$ denotes the substring from $L$th to $R$th characters of the string $S$.

In other words, you have to count number of pairs $(i, j)$ of integers such that $L \le i \le j \le R$ such that no character in substring $S[i, j]$ occurs more than $K$ times.

QUICK EXPLANATION:

Let $\text{far}[i]$ be the last index $j$ such that $S[i, j]$ has at most $K$ $0$s and at most $K$ $1$s. Then for a given query $(L, R)$, the number of valid strings starting at index $i$ is $\min(R,\text{far}[i])-i+1$ (for $L \le i \le R$). Therefore, the answer for the query $(L, R)$ is the following: $$\sum_{i=L}^R \left(\min\left(R,\text{far}[i]\right)-i+1\right)$$ Note that $\text{far}[i]$ never decreases, so we can use binary search to find the maximum index $k$ such that $\text{far}[i] \le R$. The sum then becomes: $$\sum_{i=L}^k \left(\text{far}[i]-i+1\right) + \sum_{i=k+1}^R \left(R-i+1\right)$$ Each of these is solvable in closed form, except possibly for range sums of $\text{far}[i]$. But for that, we can simply compute cumulative sums of $\text{far}[i]$.

The algorithm runs in $O(N + Q \log N)$, but can be sped up to $O(N + Q)$ by getting rid of binary search. We'll describe this below.

EXPLANATION:

We will begin by describing a slow solution, and then work on improving it incrementally. We will call a string valid if there are at most $K$ $0$s and at most $K$ $1$s.

Slow solution

First, we can simply test each substring and count all those that are valid. This can be accomplished, for example, with the following:

def answer_query(L, R):
    answer = 0
    for i in L...R
        for j in i...R
            # try the substring S[i, j]
            count0 = count1 = 0
            for k in i...j
                if S[k] == '1'
                    count1 += 1
                else
                    count0 += 1

            if count0 <= K and count1 <= K
                answer += 1

    return answer

How fast does this go? This runs proportionally to the sum of the length of all substrings of $S[L, R]$, and one can easily compute it to be approximately $\frac{(R-L+1)^3}{6}$. Since $R-L+1$ is at most $N$, in the worst case the running time is approximately $\frac{N^3}{6}$ steps. This won't pass any of the subtasks!

Breaking early

The above brute-force solution can be optimized to pass subtask 2, by the observation that valid strings are at most $2K$ in length. Therefore, we can simply check all substrings that are at most $2K$ in length, and there are $O(NK)$ of them:

def answer_query(L, R):
    answer = 0
    for i in L...R
        # process only strings up to min(2K-1,R)
        for j in i...min(i+2*K-1, R)
            # try the substring S[i, j]
            count0 = count1 = 0
            for k in i...j
                if S[k] == '1'
                    count1 += 1
                else
                    count0 += 1

                if count0 > K or count1 > K:
                    break

            if count0 <= K and count1 <= K
                answer += 1

    return answer

Notice that aside from reducing the limit of $j$ to $\min(2K+1,R)$, we have also added a break statement, because when either count0 or count1 exceeds $K$, then there is no more point in proceeding to inspect the rest of the letters, since we already know that the string wouldn't be valid.

Thus the algorithm now runs in $O(NK\min(N,K))$ time per query and $O(QNK\min(N,K))$ time overall, and passes subtask 2!

Dynamic programming

In fact, we can extend the argument we used about the break statement! Notice that the substring of a valid string is also valid, and a superstring of any invalid string is also invalid! Therefore, we can break out of the $j$ loop once we encounter an invalid string! However, this alone won't improve the code in the worst case, because it might be the case that we don't encounter an invalid string, or we encounter such a string late enough.

However, we can exploit even more properties of the substrings we are inspecting! Notice that to check whether a substring $S[i, j]$ is valid or not, we only need to count the $0$s and $1$s in it. However, this can be computed easily once we know these counts for the substring $S[i, j-1]$! Specifically, as we process the substrings $S[i, j]$ for a fixed $i$ and increasing $j$, we only need to increment count0 or count1 depending on $S[i]$:

def answer_query(L, R):
    answer = 0
    for i in L...R
        count0 = count1 = 0
        for j in i...min(i+2*K-1, R)
            # try the substring S[i, j]
            if S[j] == '1'
                count1 += 1
            else
                count0 += 1

            if count0 <= K and count1 <= K
                answer += 1
            else
                break

    return answer

Now, this runs in $O(N\min(N,K))$ time per query, and $O(QN\min(N,K))$ time overall!

However, using this might still not pass subtask 1, because there are up to $10^5$ queries. Thankfully, in subtask 1, $N$ is at most $100$, so there are only at most $N(N-1)/2$ substrings $S[L, R]$. Thus, we can simply precompute the answer for all those substrings, and then answer the $Q$ queries with a simple lookup. This approach should run in $O(N^3\min(N,K)+Q)$ and should be able to pass subtask 1!

Walking algorithm

There is still a way to optimize the above! Remember what we said above, that the substring of a valid string is also valid, and a superstring of any invalid string is also invalid. Therefore, if $S[i, j]$ is valid, then $S[i+1, j]$ is also valid!. Therefore, when we process the next $i$, we don't have to start $j$ from $i$ any more, because we already know many strings are valid from the previous $i$. Specifically, if $j'$ is the last $j$ such that $S[i, j]$ is valid, then $S[i+1, j']$ is also valid, so we can simply start iterating $j$ from $j'+1$ onwards. What's more, we can compute count0 and count1 of $S[i+1, j'+1]$ from $S[i, j'+1]$ by simply decrementing one of them depending on $S[i]$! This is illustrated in the following code:

def answer_query(L, R):
    answer = 0
    j = L
    count0 = count1 = 0
    if S[L] == '1'
        count1 += 1
    else
        count0 += 1
    for i in L...R
        while j <= R and count0 <= K and count1 <= K:
            j += 1
            if j > R
                break
            if S[j] == '1'
                count1 += 1
            else
                count0 += 1

        # at this point, we know S[i, j-1] is valid but S[i, j] is invalid
        answer += j - i

        # decrement
        if S[i] == '1'
            count1 -= 1
        else
            count0 -= 1

    return answer

Now, how fast does this go? Notice that there are still nested loops. However, every time the inner loop iterates, $j$ increases by $1$. Therefore, the inner loop runs in at most $R-L$ steps, or $O(N)$. Therefore, the whole algorithm runs in $O(N)$ time per query, and $O(QN)$ time overall! This should be able to pass subtask 1, 2 and 3.

Preprocessing and binary search

The previous algorithm is too slow for subtask 4, because it still takes $O(N)$ time per query. In fact, this is probably the fastest we can do without some sort of preprocessing, because at the very least we have to read the string $S[L, R]$ to compute the answer, and this already takes $O(N)$ time. Thus, we will try to speed up the algorithm by preprocessing.

First, note that the crucial part of the previous solution is finding, for each $i$, the first $j$ such that $S[i, j]$ is invalid, or $j > R$. However, by ignoring first the "or $j > R$" part, we see that the first such $j$ for each $i$ only depends on the string $S$! For a given $i$, let's denote that $j$ by $\text{far}[i]$ (if you read the quick explanation above, note that this $\text{far}$ is different from the $\text{far}$ there. Specifically, this one is larger by exactly $1$.). Thus, we can try to precompute $\text{far}$ at the beginning:

far[1...N]

def precompute():
    count0 = count1 = 0
    j = 1
    if S[1] == '1'
        count1 += 1
    else
        count0 += 1
    for i in 1...N
        while j <= N and count0 <= K and count1 <= K:
            j += 1
            if j > N
                break
            if S[j] == '1'
                count1 += 1
            else
                count0 += 1

        # at this point, we know S[i, j-1] is valid but S[i, j] is invalid
        far[i] = j

        # decrement
        if S[i] == '1'
            count1 -= 1
        else
            count0 -= 1

and use that for our queries:

def answer_query(L, R):
    answer = 0
    for i in L...R
        j = min(far[i], R+1) # R+1 is the first j such that j > R
        answer += j - i
    return answer

The precomputation works similarly to the previous code and runs in $O(N)$, but the queries still takes $O(N)$ time each. But now, the answer_query code is much simpler, and in fact can be expressed by the following mathematical expression $$ \sum_{i=L}^R \left(\min(\text{far}[i], R+1) - i\right) $$ We can now compute such a sum using some simple manipulations: $$\begin{align*}&= \sum_{i=L}^R \min(\text{far}[i], R+1) - \sum_{i=L}^R i \\\&= \sum_{i=L}^R \min(\text{far}[i], R+1) - \left(\frac{R(R+1)}{2} - \frac{L(L-1)}{2}\right) \end{align*}$$

However, we still got this nasty $\min$ term which we need to take care of. Thankfully, we can use the fact that $\text{far}[i]$ never decreases, to know that $\text{far}[i]$ will be $\le R$ at the beginning, and then as $i$ increases it will eventually exceed $R$, and once it does, it stays greater than $R$. Thus, it makes sense to find the last $k$ such that $\text{far}[k] \le R$, so the above expression becomes $$\begin{align*}&= \sum_{i=L}^k \text{far}[i] + \sum_{i=k+1}^R (R+1) - \left(\frac{R(R+1)}{2} - \frac{L(L-1)}{2}\right) \\\&= \sum_{i=L}^k \text{far}[i] + (R-k)(R+1) - \left(\frac{R(R+1)}{2} - \frac{L(L-1)}{2}\right) \end{align*}$$ Now, we are almost down to $O(1)$ computation, aside from two things: finding the $k$ and a range sum for $\text{far}[i]$. But these are simple. First, $k$ can be computed with binary search, as the index such that $\text{far}[k] \le R < \text{far}[k+1]$, because $\text{far}[i]$ is monotonically nondecreasing. Also, to compute range sums for $\text{far}[i]$, one can simply use cumulative sums or prefix sums: Let $\text{sumfar}[i]$ be the sum of the $\text{far}$s until the $i$th index. Then the sum $\text{far}[i] + \text{far}[i+1] + \cdots + \text{far}[j]$ is simply $\text{sumfar}[j] - \text{sumfar}[i-1]$!

These are illustrated in the following code:

far[1...N]
sumfar[0...N]

def precompute():

    # precompute far
    count0 = count1 = 0
    j = 1
    if S[1] == '1'
        count1 += 1
    else
        count0 += 1
    for i in 1...N
        while j <= N and count0 <= K and count1 <= K:
            j += 1
            if j > N
                break
            if S[j] == '1'
                count1 += 1
            else
                count0 += 1

        far[i] = j

        # decrement
        if S[i] == '1'
            count1 -= 1
        else
            count0 -= 1

    # precompute sumfar
    sumfar[0] = 0
    for i in 1...N
        sumfar[i] = sumfar[i-1] + far[i]

def answer_query(L, R):

    # binary search to find k such that far[k] <= R < far[k+1]
    # we maintain the invariant far[k1] <= R < far[k2]
    k1 = L-1
    k2 = R+1
    while k2 - k1 > 1:
        km = (k1 + k2) / 2 # here, "/" floor division
        if far[km] <= R
            k1 = km
        else
            k2 = km

    k = k1 # k is now equal to k1 because k2 - k1 = 1 and far[k1] <= R < far[k2]

    answer = sumfar[k] - sumfar[L-1] + (R-k)*(R+1) - (R*(R+1)/2 - L*(L-1)/2)

    return answer

Using this, one can see that precomputation still runs in $O(N)$ time, and queries now run in $O(\log N)$ time each, due to the binary search. Thus, the overall algorithm runs in $O(N + Q \log N)$ time, which comfortably passes all the subtasks!

Be careful with overflows! Use the right data type for this.

Bonus: $\text{far}[i]$ and $\text{raf}[i]$

The above solution already works, but we will introduce a final optimization here. Specifically, we will try to improve our algorithm to compute the $k$ in each query.

Note that $k$ is the largest index such that $\text{far}[k] \le R$ or $k < L$. The key idea is that, by ignoring first the "or $k < L$" part, we see that $k$ is only dependent on $R$! Thus it would be nice if we are able to precompute the $k$s for all possible $R$s, and in fact it is easy to do so.

Let's define a similar array $\text{raf}$, where $\text{raf}[R]$ is the smallest index $i$ such that $\text{far}[i] > R$. Using this array, one can compute $k$ simply as $\max(L,\text{raf}[R])-1$ (we'll leave this to the reader to see why). Now, how do we compute all the $\text{raf}$s? The idea is that $\text{raf}$ is essentially the reverse of $\text{far}$, only that the direction is to the left rather than to the right. Thus, a similar $O(N)$ time walking algorithm can be used to compute it. We will leave this as an exercise for the reader, however, because we will show here a different way to compute it in $O(N)$ time, by exploiting the relationships between $\text{far}$ and $\text{raf}$. See the following pseudocode for details:

far[1...N]
raf[1...N]
sumfar[0...N]

def precompute():

    # precompute far
    .....

    # precompute sumfar
    ....

    # precompute raf
    # initialize
    for i in 1...N
        raf[i] = -1

    # we know that far[i]-1 < far[i], so if j = far[i]-1,
    # then raf[j] must be <= i, (because raf[j] is the least such i)
    # we process each i in decreasing order to guarantee that we assign the least such i
    for i in N...1 by -1
        raf[far[i]-1] = i

    # for all the raf[i]'s that we didn't encounter, set its value to raf[i+1]
    # because raf[i] <= raf[i+1]
    for i in N...1 by -1
        if raf[i] == -1
            raf[i] = raf[i+1]

def answer_query(L, R):

    k = max(L, raf[R])-1
    answer = sumfar[k] - sumfar[L-1] + (R-k)*(R+1) - (R*(R+1)/2 - L*(L-1)/2)
    return answer

Finally, one can now see that it runs in $O(1)$ time per query, and $O(N + Q)$ time overall!

Time Complexity:

$O(N + Q)$

AUTHOR'S AND TESTER'S SOLUTIONS:

Setter
tester

EMBED - Editorial (It is just a template for now, Please discuss your ideas here)

CHEFCH - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Dmytro Berezin
Tester:Pushkar Mishra
Editorialist:Florin Chirica

PROBLEM

You're given a string of $+$ and $-$ symbols. A string is called a chain if it does not have two or more equal characters. Our target is to convert the given string into a chain. For doing that, you can flip a character (from $+$ to $-$ and vice versa) of the string. Find out minimum number of flips needed.

QUICK EXPLANATION

We can notice that by fixing the first character, the rest of the chain is also fixed. There are two ways to fix the first character, by putting either $+$ or $-$. For both of these possibilities, we can find minimum number of flips needed and take minimum of both to get our final answer.

EXPLANATION

Fixing first character fixes entire chain

We can notice that by fixing the first character, the rest of the chain is also fixed.

If the first character is $+$, the second one must be $-$, the third one must be + and so on. So, the final string will be something like $+-+-+-$ which is a valid chain.

Similarly, we can say the same when the first character of chain is $-$.

Computing minimum number of flips needed to convert a string $init$ into a fixed chain $fin$

Given two strings $init$ and $fin$ ($init$ is the initial string, $fin$ is the desired chain), the task now becomes to compute number of positions $i$ where $init[i] \neq fin[i]$. If we find such a position, we're forced to make a flip. Otherwise, we don't need any flip.

Computing the final answer

There are two possibilities for chain $fin$ given as follows.

  • $+-+- \dots$
  • $-+-+- \dots$

So we can try each one of these. For each case, we can compute the number of differing position between it and the initial array as stated above.

As we have to find overall minimum number of flips needed, we can take minimum of both of these cases.

Time Complexity

Since computing the number of differing position between two strings of size $n$ takes $O(n)$ time. We do this for two cases, so the overall complexity is also $O(n)$.


Subtask 1 Solution
As length of string $s$ is very small ($|s| \leq 10$), we can brute-force over all possible flips in $s$. As each character can be either $+$ or $-$, there are total $2^n$ possibilities which will be at max $1024$ for the given $n$.

Time Complexity
We are brute-forcing over all possible $2^n$ strings, for a fixed string we need $\mathbb{O}(n)$ time. So overall time required will $\mathbb{O}(2^n * n)$

AUTHOR'S AND TESTER'S SOLUTIONS:

Tester's solution

Setter's solution

CHEFEQ - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Abhra Dasgupta
Tester:Pushkar Mishra
Editorialist:Florin Chirica

PROBLEM

Let's formalize the problem. Suppose you're given an array read from the input.

Operation #1: Pick some coins from any pile and put them back in Chef's coin box.

This means we can decrease the number of coins from any pile.

Operation #2: Pick some coins from the Chef's coin box and put them on any one pile.

This means we can increase the number of coins from any pile.

Observations #1 and #2 combined tell us we can change the number of conins from any pile to what number we want. Our goal is to have the same value in each pile.

QUICK EXPLANATION

The trick is to find the most frequent value and make all array equal to that value.

EXPLANATION

Picking the most frequent value

So you get an array and you can change what element you want. What's the minimal number of changes in order to get all elements equal?

Denote x as the value in the array after we finish all operations. Obviously, x must be a value from the initial array. A brute force algorithm could be taking 1st element, 2nd element, ..., nth element and assume it is x. Then, calculate the cost and pick the minimal cost. However, this takes O(n ^ 2), which is too much for get full score.

Let's try something else. After we pick an x, the cost is equal to number of elements that have different value from x. This cost is also n - number of elements that have the same value with x. Since n is constant, we need to minimize expression: (-(number of elements that have the same value with x)), or maximize the expression (number of elements that have same value with x). (We got this considering that if -a is minimized, then a will be maximized).

So maximizing number of elements that have the same value with x can be done by finding the most frequent element from the array.

Finding the most frequent element of the array

We'll present two ways to get it:

First way is based on the small values for A[i] elements. We can keep an array count[x] = how many times does value x appear in the array. Then, we can iterate elements of count from 0 to 10^5 (the upper limit for A[i]) and store the maximum.

The second way is based on the fact that elements having the same value form a contiguous subsequence in the sorted array. So we sort our array and divide it in "blocks" having the same value. An element x will appear in exactly one block of elements having the same value. This approach can be used to solve the problem even if we're not given A[i] <= 10^5 restriction.

Depending on how you implement it, the complexity is either $O$(n + maximumValue) or $O$(n * log(n)).

AUTHOR'S AND TESTER'S SOLUTIONS:

Tester's solution
Setter's solution


RANKLIST - editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Chandan Boruah
Tester:Pushkar Mishra
Editorialist:Florin Chirica

PROBLEM

Let's define a ranklist as a sequence of numbers between 1 and x of length n, such as ALL numbers between 1 and x must appear in the sequence at least once. An operation can change one element in what value you want. Your goal is to create a sequence containing all numbers between 1 and n exactly once by using minimal number of operations.

QUICK EXPLANATION

Let's iterate a number x meaning that all numbers between 1 and x appear in the ranklist. The cost of any ranklist with values between 1 and x is n - x. We need to determine if numbers between 1 and x are enough to create a sum s. Let's note that a ranklist defined by x can create all sums between minSum and maxSum, where minSum = x * (x + 1) / 2 + (n - x) and maxSum = x * (x + 1) / 2 + (n - x) * x.

EXPLANATION

To solve this problem, we need to make two observations. They seem pretty easy and intuitive, but after we make them, the problem is solved.

Observation 1

A ranklist containing elements between 1 and x (no element greater than x) will need n - x operations to be transformed into a sequence of numbers between 1 and n, no matter how sequence looks like.

We already have all elements between 1 and x (from the definition of a ranklist). However, we need to also have elements x + 1, x + 2, ..., n - 1, n. Those do not appear (since all are greater than x), so we have to make some operations to get them. We can keep exactly one position which contains a value i, for each i between 1 and x. Rest of n - x positions must be modified. We'll put in the remaining n - x positions values x + 1, x + 2, ..., n - 1 and n. So cost of a ranklist containing elements between 1 and x becomes n - x.

Observation 2

A ranklist containing elements between 1 and x (no element greater than x) can generate all sums s, such as minSum <= s <= maxSum. More, all sums that can be generated by this ranklist are the ones that are between minSum and maxSum.

Let's find out who is minSum. We are forced to place x elements: 1 2 .... x. The rest of them we can complete them with 1s. So minSum = (1 + 2 + ... + x) + (n - x) = x * (x + 1) / 2 + (n - x). maxSum can be obtained by completing the first x elements 1 2 ... x and the rest of them with x value (the maximum we're allowed to use). So we get maxSum = (1 + 2 + ... + x) + (n - x) * x = x * (x + 1) / 2 + (n - x) * x.

Obviously, no sum s can be less than minSum or greater than maxSum (because those values are the minimum/maximum one can get). Let's proof now that each sum s which has minSum <= s <= maxSum can be obtained. The idea is to see how those n - x terms can vary: they can be from 1 1 1 ... 1 1 1 to x x x ... x x x. Suppose we obtained a configuration corresponding to a sum s. Unless s is equal to maxSum, we can always obtain s + 1 as well. If s equal to maxSum, then all terms are equal to x. Otherwise, at least one term isn't x. Since it isn't x, we can increment it. Now, the obtained sum is s + 1 and it's obtained assuming that s is different from maxSum.

Putting the observations together

In fact, those 2 observations are enough to solve the problem. The key that puts them together is that we can iterate x from 1 to n. Let's see for a fixed x if a sum s can be obtained. For the given x, we can calculate minSum and maxSum and if minSum <= x <= maxSum, then sum s can be obtained and a ranklist containing only values between 1 and x is valid. The cost to transform this ranklist into 1 2 ... n is n - x. So, for all valid ranklists (those who can give sum s), we keep minimum of n - x and we're done.

Time Complexity

Since we iterate the x variable from 1 to n, the complexity is $O(n)$.

AUTHOR'S AND TESTER'S SOLUTIONS:

Tester's solution
Setter's solution

STRQ - editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Sunny Aggarwal
Tester:Pushkar Mishra
Editorialist:Florin Chirica

PROBLEM

You're given a string containing only letters c h e and f. You have to answer queries asking how many words start in a given letter and end in other letter (necessarily different by first one) considering only positions from the string between two given numbers.

QUICK EXPLANATION

Let's calculate ways[A][B][i] = in how many ways can we choose a word with beginning letter A, ending letter B and its ending position up to i. Also, let cnt[A][i] = how many letters A appear in the first i characters. This information is enough to answer queries in O(1): for two characters A and B and two positions i and j, the answer is ways[A][B][j] - ways[A][B][i - 1] - cntA * cntB, where cntA = number of characters equal to A from [1...i - 1] and cntB = number of characters equal to B from [i...j].

EXPLANATION

Number of letters is small

A first thing we should observe is the number of letters available is 4 (c h e and f). This low number of letters will help us to solve the problem with a simple and efficient solution.

The idea with having 4 letters is that we can precalculate something, then we can answer all queries in constant time.

Let's inspect how queries can look like. We start by looking how beginning and ending of a good substring can look like. There are only 12 possibilities.

  • (start) c (end) h
  • (start) c (end) e
  • (start) c (end) f
  • (start) h (end) c
  • (start) h (end) e
  • (start) h (end) f
  • (start) e (end) c
  • (start) e (end) h
  • (start) e (end) f
  • (start) f (end) c
  • (start) f (end) h
  • (start) f (end) e

Since there are only 12 possibilities, we can iterate over them and store something for each configuration. For a configuration, what we computed should be enough to solve all queries that correspond to that configuration.

For a fixed start and end letter

By now we can assume that our start and end letters are fixed (using the iteration). Let's denote by A the start letter and by B the end letter.

What we need to do is to answer queries: for a subarray [i...j], how many indices i', j' exist, such as array[i'] = A and array[j'] = B, with i <= i' <= j' <= j.

The trick here is to solve an easier problem firstly: suppose we only had to count pairs (i', j') such as i' <= j' <= j (we erased i condition). Now the task can be solved by a simple precalculation.

Let ways[A][B][i] = number of ways to choose i' <= j' <= i such as array[i'] = A and array[j'] = B. We have two choices for j'.

Choice #1: Let j' < i. All pairs (i', j') such as j' < i are already calculated in ways[A][B][i - 1], so we can simply add this number and treat all case. Choice #2: Let j' = i. Obviously, for this to happen we're forced to have array[i] = B. What's left is to find positions i' such as array[i'] = A and i' < i. This is easily done by keeping a partial sum for each letter, something like sum[let][i] = how many times does letter let appear in positions [1...i].

Hence, the answer is in ways[A][B][j].

Now let's consider full restrictions. In reality we have i <= i' <= j' <= j. Let's see what elements are counted above, but should not be counted.

There are two cases

Case #1: i' < j' < i <= j

Case #2: i' < i < j' <= j

We have to erase from our result the results for those cases.

Case #1 is simple to calculate, as its answer is simply ways[A][B][i - 1].

Case #2 basically asks us to find a letter A in range [1...i - 1] and a letter B in range [i...j]. Let cntA the number of letters A in range [1...i-1] and cntB the number of letters B in range [i...j]. The answer is simply cntA * cntB. The values of cntA and cntB can be calculated by partial sums.

Time Complexity

The computation of ways takes $O(n)$ time (with constant 12). Also, partial sums also take $O(n)$ time. Then, a query is answered in $O(1)$ as stated above.

AUTHOR'S AND TESTER'S SOLUTIONS:

Tester's solution
Setter's solution

CUSTPRIM - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Kevin Atienza
Tester:Jingbo Shang and Pushkar Mishra
Editorialist:Kevin Atienza

CREDITS

Special thanks to the author of the problem for providing a detailed explanation.

DIFFICULTY

hard

PROBLEM

Payton numbers are defined, and prime Payton numbers are defined. Given a Payton number, is it prime or not? (Please see the problem statement for more details)

QUICK EXPLANATION

First, the term "prime" defined in the problem statement actually refers to the abstract-algebraic term "irreducible", and the term "prime" itself is defined differently. Thankfully, as we shall see below, the primes and irreducibles in Payton numbers coincide.

Let $\omega$ be a symbol such that $\omega^2 = \omega - 3$. Then there is an isomorphism between the Payton numbers and the Euclidean domain $\mathbb{Z}[\omega]$ given by $\phi(a,b,c) = (33-2a-c)+(b-a)\omega$. This means that the Payton numbers also form a Euclidean domain (thus primes are the same as irreducibles), and that we have reduced the problem to a primality check in $\mathbb{Z}[\omega]$.

In $\mathbb{Z}[\omega]$, all elements $x$ are of the form $x = a + b\omega$ where $a, b \in \mathbb{Z}$. If we define the norm of $x$ (denoted as $Nx$) as $a^2 + ab + 3b^2$, then we can show the following:

  • If $x$ is an integer (i.e. $b = 0$), then $x$ is prime if and only if $x$ is a prime integer, and either $x = \pm 2$ or $x \not= \pm 11$ and $-11$ is not a quadratic residue modulo $x$.
  • If $x$ is not an integer (i.e. $b \not= 0$), then $x$ is prime if and only if $Nx$ is a prime integer.

This yields an efficient solution to the problem as long as we can quickly check whether an ordinary integer is prime, and we can quickly check whether $-11$ is a quadratic residue modulo a prime. Primality checking is a standard problem which can be solved using the Miller-Rabin test for example, and checking whether $-11$ is a quadratic residue modulo a prime can be done with Euler's criterion.

EXPLANATION

Denote $S$ as the set of Payton numbers.

Primes in $S$

Let $\omega$ be a symbol such that $\omega^2 = \omega - 3$. Then we can define addition and multiplication in the set $\mathbb{Z}[\omega] = \{a + b\omega : a, b \in \mathbb{Z}\}$ naturally, and the resulting structure is actually a principal ideal domain (we'll discuss this below).

In fact, $S$ is isomorphic to $\mathbb{Z}[\omega]$! This means that the structure of $S$ and $\mathbb{Z}[\omega]$ are identical. In other words, $S$ is just $\mathbb{Z}[\omega]$ with its elements simply relabeled or renamed.

Define $\phi$ as a map from $S$ to $\mathbb{Z}[\omega]$ where $\phi(a,b,c) = (33-2a-c)+(b-a)\omega$. Then $\phi$ is an isomorphism, i.e. a bijective map that satisfies:

$$ \phi(a+b) = \phi(a) + \phi(b) $$ $$ \phi(ab) = \phi(a)\phi(b) $$

The inverse of $\phi$ can be written as the following:

$$ \phi^{-1}(a+b\omega) = \begin{cases} (11-k,11-k+b,11) & \text{if $a$ is even and $a = 2k$} \\\ (4-k,4-k+b,24) & \text{if $a$ is odd and $a = 2k+1$} \end{cases} $$

This is great, because this means that the properties of $S$ are exactly the same with $\mathbb{Z}[\omega]$. For instance, an element $x$ of $S$ is prime in $S$ if and only if $\phi(x)$ is prime in $\mathbb{Z}[\omega]$. Therefore, we can study the primes in $\mathbb{Z}[\omega]$ instead.

How to find this isomorphism

Now, you might be wondering: how does one discover this isomorphism? To be honest, I don't know of any surefire way to do this. Even inspecting the accepted solutions doesn't help much, because we can't see the process of discovery there. But a possible line of attack might be:

  • Play around with multiplication and realize it is commutative, and also associative if you're lucky. This suggests that it might be isomorphic to some well-known ring.
  • Realize that multiplication is symmetric in $a$ and $b$, and that the Payton "zero" and "unity" both satisfy $a = b$. This suggests studying the Payton numbers where $a = b$ would be fruitful. If you're lucky enough, you might notice that this subring is isomorphic to the ring of ordinary integers ($(a,a,c)$ pairs with the integer $33-2a-c$).
  • Realize that Payton numbers are really just two-dimensional, and (using the knowledge of a subring isomorphic to the integers) guess that they must be isomorphic to a quadratic integer ring. Discovering which ring it is might take some experimentation, but I would guess that the worst is behind at this point.

Primes in $\mathbb{Z}[\omega]$

Notice that one can write $\omega = \frac{1+\sqrt{-11}}{2}$. First, we show that $\mathbb{Z}[\omega]$ is a Euclidean domain. A Euclidean domain $R$ is an integral domain endowed with a Euclidean function, which is a function $f$ from $R$ to $\mathbb{N}$ satisfying the following property:

If $a$ and $b$ are in $R$ and $b \not= 0$, then there exists $q$ and $r$ in $R$ such that $a = bq + r$ and either $r = 0$ or $f(r) < f(b)$.

In the case of $\mathbb{Z}[\omega]$, the Euclidean function we will use is $f(a+b\omega) = a^2+ab+3b^2$. Notice that if one writes $\omega = \frac{1+\sqrt{-11}}{2} = \frac{1}{2}+\frac{\sqrt{11}}{2}i$, then $f(x+yi)$ is just $x^2+y^2$, which is just the square of the distance to the origin $0+0i$ of the complex plane.

Our proof requires a property of the field $\mathbb{Q}[\omega] = \{a + b\omega : a, b \in \mathbb{Q}\}$. Notice that $f$ can be naturally generalized to include $\mathbb{Q}[\omega]$ in its domain, though the codomain of $f$ becomes $\mathbb{Q}$.

Claim

For every element $x$ of $\mathbb{Q}[\omega]$, there exists an element $n$ in $\mathbb{Z}[\omega]$ such that $f(x-n) < 1$.

Proof

Let's call $x$ good if there exists an $n$ in $\mathbb{Z}[\omega]$ such that $f(x-n) < 1$, so we are trying to prove that all elements of $\mathbb{Q}[\omega]$ are good. The following are facts about goodness (simple to show):

  • Let $m\in \mathbb{Z}[\omega]$. Then $x\in \mathbb{Q}[\omega]$ is good if and only if $x-m$ is good.
  • $x\in \mathbb{Q}[\omega]$ is good if and only if $-x$ is good.

Therefore, if $a+b\omega$ is an element of $\mathbb{Q}[\omega]$, then the element $\lfloor a \rfloor + \lfloor b \rfloor \omega$ is an element of $\mathbb{Z}[\omega]$. So $a+b\omega$ is good if and only if $(a+b\omega) - (\lfloor a \rfloor + \lfloor b \rfloor \omega) = (a-\lfloor a \rfloor) + (b - \lfloor b \rfloor \omega)$ is good. Thus we have reduced the general case to the case where $0 \le a < 1$ and $0 \le b < 1$. Also, note that if $a + b > 1$, then $a+b\omega$ is good if and only if $-a-b\omega$ is good, if and only if $-a-b\omega+(1+\omega) = (1-a)+(1-b)\omega$ is good. Thus we have further reduced the case to the case where $a \ge 0$, $b \ge 0$ and $a + b \le 1$.

Finally, assume $a \ge 0$, $b \ge 0$ and $a + b \le 1$. Then, considering $a+b\omega$ as a point in the complex plane with $\omega = \frac{1+\sqrt{11}i}{2}$, we have that $a + b\omega$ is inside the triangle bounded by vertices $0+0\omega = 0+0i$, $1+0\omega = 1+0i$ and $0+1\omega = \frac{1}{2} + \frac{\sqrt{11}}{2}i$. The vertices are elements of $\mathbb{Z}[\omega]$. Inside this triangle, the point farthest from any vertex is the circumcenter of the triangle, which can be easily calculated as $\frac{1}{2}+\frac{5}{2\sqrt{11}}i$. The norm of this number minus each of the vertices is $9/11 < 1$, so the claim is proven for $a+b\omega$ (take the nearest vertex).

End proof

We can now show that $\mathbb{Z}[\omega]$ is a Euclidean domain. Note that division is defined in $\mathbb{Q}[\omega]$, and that $f(ab) = f(a)f(b)$ for any $a$ and $b$ (Hint: consider $a$ and $b$ as complex numbers).

Claim

$\mathbb{Z}[\omega]$ is a Euclidean domain with the Euclidean function $f(a+b\omega) = a^2+ab+3b^2$.

Proof

Let $a$ and $b$ be in $\mathbb{Z}[\omega]$, and $b \not= 0$. Note that $a/b$ is an element of $\mathbb{Q}[\omega]$. By the claim above, there exists a $q$ in $\mathbb{Z}[\omega]$ such that $f(a/b-q) < 1$. Let $r = a - qb$. Then $f(r/b) < 1$, so $$ f(r) = f(r/b\cdot b) = f(r/b)f(b) < 1f(b) = f(b) $$ and the Euclidean property is satisfied, QED.

End proof

Being a Euclidean domain is very nice. For instance, greatest common divisors are well-defined and always exist. Also, every Euclidean domain is a principal ideal domain (PID). It is a well-known fact that every PID is a unique factorization domain (UFD), which means that every number can be written uniquely as a product of primes and a unit.

It is also true in UFDs that irreducible elements are the same as prime elements. Note that irreducible and primes are actually distinct, although we are used to the idea that these are the same, because they are the same in the domain of integers. Also, note that the definition given in the problem statement is actually that of irreducible elements, not prime elements, but since these are the same in a UFD, there's no problem.

In number theory, we say that $a$ divides $b$ in $R$, denoted as $a \mid b$, if there is a $c$ in $R$ such that $ac = b$. We say that $x \in R$ is a unit if $x \mid 1$ in $R$ (in the ring of integers, the units are precisely $-1$ and $1$, and in the Payton numbers, $(4,4,24)$ and $(5,5,24)$). A non-unit $p$ is irreducible if $p$ cannot be factorized into non-units (i.e. if $p = ab$, then either $a$ or $b$ is a unit), and a non-unit $p$ is prime in $R$ if $p \mid ab$ implies $p \mid a$ or $p \mid b$.

We now define greatest common divisors. We say that $g$ is a greatest common divisor, or gcd, of $a$ and $b$ if every common divisor of $a$ and $b$ divides $g$. Note that we say a gcd instead of the gcd because there can be many greatest common divisors of $a$ and $b$. For example, if $g$ is a gcd of $a$ and $b$, then $-g$ is also a gcd. However, it is also true that if $g_1$ and $g_2$ are gcd's of $a$ and $b$, then $g_1 = ug_2$ for some unit $u$ (this follows from the easily provable fact that $x \mid y$ and $y \mid x$ implies $x = uy$ for some unit $u$).

We now show that gcd is well-defined:

Claim

Every pair $(a,b)$ of values in a Euclidean domain $R$ has a gcd.

Proof

If $b$ is zero, then $a$ is a gcd, because every element $r$ in $R$ divides $0$ (because $r0 = 0$). Therefore, the common divisors of $a$ and $0$ are simply the divisors of $a$. If $b$ is nonzero, then we prove the claim by induction on $f(b)$ (which makes sense because $\mathbb{N}$ is well-ordered). Let $a = bq + r$ with $r = 0$ or $f(r) < f(b)$.

If $r = 0$, then $b$ is a gcd of $a$ and $b$, because every divisor of $b$ is also a divisor of $bq = a$. If $f(r) < f(b)$, then by induction, $b$ and $r$ has a gcd, say $g$. We claim that $g$ is also a gcd of $a$ and $b$. This is because every common divisor of $a$ and $b$ also divides $a-bq = r$, so by definition of gcd, it also divides $g$, thus proving that $g$ is a gcd of $a$ and $b$. QED.

End proof

Note that this proof is analogous to the Euclidean gcd algorithm. In fact, this is why $R$ is called a Euclidean domain.

We now prove Bezout's identity in Euclidean domains.

Claim

If $g$ is a gcd of $a$ and $b$ in $R$, then there exists $x$ and $y$ in $R$ such that $ax + by = g$.

Proof

If $b = 0$, then $a$ is a common divisor of $a$ and $b$, and since $g$ is a gcd, $a \mid g$, therefore, $g = ac$ for some $c$. This means that $ca + 0b = g$ (i.e. $(x,y) = (c,0)$). If $b$ is nonzero, then we prove the claim by induction on $f(b)$. let $a = bq + r$ with $r = 0$ or $f(r) < f(b)$.

If $r = 0$, then $b$ is a common divisor of $a$ and $b$, and since $g$ is a gcd, $b \mid g$, therefore $g = bc$ for some $c$. This means that $0a + cb = g$ (i.e. $(x,y) = (0,c)$. If $f(r) < f(b)$, then $g$ is also a gcd of $b$ and $r$, so by induction there exists $x'$ and $y'$ such that $x'b + y'r = g$. Then $y'a + (x' - qy')b = g$ (i.e. $(x,y) = (y', x' - qy')$). QED.

End proof

Note that this is analogous to the extended Euclidean gcd algorithm.

Define the conjugate of $a + b\omega$ as $a + b - b\omega$, and denote it as $(a + b\omega)'$. The conjugate has the following nice properties (which are easy to prove and are left as exercises):

  • $x'' = x$
  • $(x + y)' = x' + y'$
  • $(xy)' = x'y'$
  • $x$ is prime if and only if $x'$ is prime.
  • If $x \mid y$, then $x' \mid y'$
  • If $g$ is a gcd of $a$ and $b$, then $g'$ is a gcd of $a'$ and $b'$
  • $x$ is an integer if and only if $x' = x$
  • $x + x'$ is an integer. This quantity is called the trace of $x$. The trace of $a + b\omega$ is $2a + b$.
  • $xx'$ is an integer. This quantity is called the norm of $x$.

The norm is actually important for our purposes. It is denoted as $Nx$ (i.e. $Nx = xx'$), and has the following properties (which are also easy to prove and are left as exercises):

  • $N(a+b\omega) = a^2+ab+3b^2$. Note that this coincides with the Euclidean function $f$ we used above.
  • $Nx \ge 0$.
  • $Nx = 0$ if and only if $x = 0$.
  • $Nx = N(x')$
  • $x \mid Nx$
  • If $x \mid y$, then $Nx \mid Ny$.
  • $N(xy) = Nx\cdot Ny$. It follows that if $x$ is a unit, then $Nx = 1$.
  • $Nx = 1$ if and only if $x = 1$ or $x = -1$. It follows that the only units in $\mathbb{Z}[\omega]$ are $1$ and $-1$.

We now begin to uncover exactly which elements of $\mathbb{Z}[\omega]$ are prime. We begin with the following:

Claim

If $x$ is a non-unit in $\mathbb{Z}[\omega]$ and $Nx = p$ for some prime integer $p$, then $x$ is prime.

Proof

If $yz = x$, then $Ny\cdot Nz = N(yz) = Nx = p$. Therefore, either $Ny$ or $Nz$ is $1$, so either $y$ or $z$ is a unit. Therefore, $x$ is irreducible, so $x$ is prime, QED.

End proof

Next, we show that the norms of prime elements are actually very limited in form:

Claim

If $x$ is prime in $\mathbb{Z}[\omega]$, then $Nx$ is either a prime integer or a square of a prime integer.

Proof

Factorize the integer $Nx$ as $Nx = p_1\cdot p_2\cdots p_k$. Now $x$ divides $Nx$, and since $x$ is prime, $x$ therefore divides some $p_i$. Therefore, $Nx \mid Np_i = p_i^2$. So $Nx$ can be $1$, $p_i$ or $p_i^2$. But $x$ is not a unit, so $Nx$ is a prime or a square of a prime, QED.

End proof

Now, a normal composite integer is also composite in $\mathbb{Z}[\omega]$, because its integer factorization is also valid in $\mathbb{Z}[\omega]$. However, not all prime integers are primes in $\mathbb{Z}[\omega]$. The following describes a family of prime integers which are not prime in $\mathbb{Z}[\omega]$.

Claim

If $p$ is an odd prime, $p \not= \pm 11$, and if $-11$ has a square root mod $p$, then $p$ is factorable as $p = xx'$, where $x$ and $x'$ are primes in $\mathbb{Z}[\omega]$.

Proof

Let $a$ be a square root of $-11$ mod $p$ (i.e. $a^2 \equiv -11 \pmod{p}$). Note that $p$ divides $a^2+11$.

Now, let $x$ be a gcd of $p$ and $a+1-2\omega$. By Bezout, there exist $A$ and $B$ such that $x = Ap+B(a+1-2\omega)$. By taking conjugates, and noting that $p' = p$ and $(a+1-2\omega)' = (a-1+2\omega)$, we see that $x'$ is a gcd of $p$ and $a-1+2\omega$, and $x' = Ap + B(a-1+2\omega)$.

Thus, $$ xx' = (Ap+B(a+1-2\omega))(Ap+B(a-1+2\omega)) $$ $$ = A^2p^2+ABp(2a)+B^2(a^2+11) $$ $$ = p[A^2p+AB(2a)+B^2(a^2+11)/p] $$ So $Nx = xx'$ is divisible by $p$, and $x$ is not a unit. Thus $x'$ is also not a unit.

Now, let $g$ be a gcd of $x$ and $a-1+2\omega$. Thus there exists $C$ and $D$ such that $Cx + D(a-1+2\omega) = g$. Now, since $x \mid (a+1-2\omega)$, we have $g \mid (a+1-2\omega)$. Thus, $g \mid (a+1-2w)+(a-1+2w) = 2a$. Thus, $g$ is a common factor of $2a$ and $p$. But $2a$ and $p$ are coprime, so $g \mid 1$, and $gh = 1$ for some $h$.

Thus: $$ Cx + D(a-1+2\omega) = g $$ $$ Chx + Dh(a-1+2\omega) = gh = 1 $$ $$ Ch(xp) + Dhp(a-1+2\omega) = p $$ Now, $x'$ divides $p$, so $xx'$ divides $xp$. Also, $x$ divides $p$ and $x'$ divides $a-1+2\omega$, so $xx'$ divides $p(a-1+2\omega)$. Therefore, $xx'$ divides $Ch(xp) + Dhp(a-1+2w) = p$.

Now, $Nx = xx'$ divides $p$ and is divisible by $p$, therefore $xx' = p$. Thus, $p$ is product of non-units $x$ and $x'$. Furthermore, $Nx = N(x') = p$, so $x$ and $x'$ are prime, QED.

End proof

The following shows that the converse is also true:

Claim

If $p$ is a prime and $p \not= \pm 11$, and $-11$ doesn't have a square root mod $p$, then $p$ is irreducible in $\mathbb{Z}[\omega]$.

Proof

We prove the contrapositive.

If $p$ is reducible as $xy = p$ with non-units $x$ and $y$, then $Nx\cdot Ny = Np = p^2$. Since $x$ and $y$ are non-units, the only possibility is $Nx = Ny = p$. Now, let $x = a+b\omega$. Then: $$ p = Nx $$ $$ p = a^2+ab+3b^2 $$ $$ 4p = 4a^2+4ab+12b^2 $$ $$ 4p = (2a+b)^2+11b^2 $$ $$ 0 \equiv (2a+b)^2+11b^2 \pmod{p} $$ $$ (2a+b)^2 \equiv -11b^2 \pmod{p} $$ $$ [(2a+b)b^{-1}]^2 \equiv -11 \pmod{p} $$ This means that $(2a+b)b^{-1} \bmod p$ is a square root of $-11$ mod $p$. Note that $b$ is invertible mod $p$ because if $p \mid b$, then $p$ also divides $p - ab - 3b^2 = a^2$, so $p \mid a$. This means that $p \mid a + b\omega = x$, and $p^2 = Np \mid Nx = p$, a contradiction, QED.

End proof

These two claims cover most of the primes. The only ones not covered are $\pm 2$ and $\pm 11$. Luckily, they can be easily checked by hand: $11$ and $-11$ are not prime because $-11 = (1-2\omega)^2$ and $11 = -(1-2\omega)^2 = (1-2\omega)(1-2\omega)'$, and it can easily be shown that $2$ and $-2$ are prime (Hint: Show that there doesn't exist $x$ such that $Nx = 2$).

Next, we describe the rest of the prime elements of $\mathbb{Z}[\omega]$. Let $x$ be a prime. We have shown above that that $Nx$ should be a prime or a square of a prime. If $Nx$ is prime, we have shown above that $x$ is prime. Now, what if $Nx$ is the square of a prime? The following shows that $x$ is an integer:

Claim

If $x$ is prime and $Nx = p^2$, then $x = \pm p$.

Proof

First, if $p$ cannot be factored in $\mathbb{Z}[\omega]$, then the only nontrivial factorizations of $p^2$ are $p\cdot p$ and $-p\cdot -p$. Since $xx' = p^2$, then $x = \pm p$.

If $p$ can be factorized in $\mathbb{Z}[\omega]$ into two primes $p = yy'$, then $p^2 = yy'yy' = y^2(y')^2$. Thus, the only factors of $p^2$ whose norm is $p^2$ are $\pm y^2$, $\pm yy'$ and $\pm (y')^2$, and $x$ can only be one of those. But none of those are prime, so this case is impossible.

End proof

We can now combine all of the above to characterize the primes in $\mathbb{Z}[\omega]$. Let element $x$ be an element of $\mathbb{Z}[\omega]$. Then:

  • If $x$ is not an integer, then $x$ is prime if and only if $Nx$ is a prime integer.
  • If $x$ is an integer, then $x$ is prime if and only if $x$ is a prime integer, and either $x = \pm 2$ or $x \not= \pm 11$ and $-11$ is not a quadratic residue modulo $x$.

Checking whether an integer $p$ is prime can be done with Miller-Rabin.

Checking whether $-11$ is a quadratic residue modulo a prime $p$ can be done using the Legendre symbol $\left(\frac{a}{p}\right)$, which is defined as: $$ \left(\frac{a}{p}\right) = \begin{cases} 0 & \text{if $p \not\mid a$} \\\ 1 & \text{if $p\mid a$ and $a$ is a quadratic residue modulo $p$} \\\ -1 & \text{if $p \mid a$ and $a$ is not a quadratic residue modulo $p$} \end{cases} $$

By Euler's criterion, this can be calculated in $O(\log p)$ time as: $$ \left(\frac{a}{p}\right) \equiv a^{\frac{p-1}{2}} \pmod{p} $$

Note that you could also use the law of quadratic reciprocity to more quickly check whether $-11$ is a quadratic residue: $-11$ is quadratic modulo an odd prime $p$ if and only if $p \equiv 0, 1, 3, 4, 5, \text{ or } 9 \pmod{11}$ (i.e. those odd $p$'s which are quadratic residues modulo $11$).

SUMMARY

We now summarize the algorithm.

def is_prime_integer(k) {
   // returns whether k is a prime integer.
   // you can use something like Miller-Rabin for this.
}

def is_prime(a,b,c) {
    A := 33 - 2*a - c
    B := b - a
    if (B = 0) {
        return |A| = 2 or (
            is_prime_integer(|A|) and
            modpow(-11,(|A|-1)/2,|A|) = |A|-1
        );
    } else {
        return is_prime_integer(A*A + A*B + 3*B*B);
    }
}

CHEFSTON - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Dmytro Berezin
Tester:Shiplu Hawlader
Editorialist:Lalit Kundu

DIFFICULTY:

CAKEWALK

PRE-REQUISITES:

Basic Maths

PROBLEM:

There are total N kinds of stones. There is unlimited supply of each kind of stone.
Chef knows that one stone of kind i needs Ai minutes to pick it from the ground and it will give Chef a profit of Bi Rs.
Chef has K minutes of free time. During this free time, Chef want to pick stones so as to maximize his profit. But he can not pick stones of different kinds, he has to pick stones of a single kind. Please help Chef to find the maximal possible profit.

EXPLANATION:

We traverse over each kind of stone assuming that he will pick that kind of stone and calculate profit in that case.
So, if it takes x minutes to pick up one stone(which gives a profit of y), in K minutes, you will pick up K/x stones(note the division is integer division). So profit in such a case will be (K/x) * y.

Pseudo Code:

ans=-1
for i=1 to N:
    ans = max(ans, (K/A[i])*B[i])

Note that we'll need to use 64-bit integers because of higher constraints.

Complexity: O(N).

SOLUTIONS:

Setter's solution
Tester's solution

GCDQ - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Praveen Dhinwa
Tester:Shiplu Hawlader
Editorialist:Lalit Kundu

DIFFICULTY:

EASY

PRE-REQUISITES:

GCD, Precomputation

PROBLEM:

You are given an array A of integers of size N. You will be given Q queries where each query is represented by two integers L, R. You have to find the gcd(Greatest Common Divisor) of the array after excluding the part from range L to R inclusive (1 Based indexing). You are guaranteed that after excluding the part of the array remaining array is non empty.
1 ≤ N, Q≤ 100000

EXPLANATION:

If you do it naively(ie. calculating GCD of remaining array for each query), the worstcase complexity will be O(N * Q).
Let's denote by G(L, R), the GCD of AL, AL+1 ... AR. We can observe that for query [L, R], we need GCD of G(1, L-1) and G(R+1, N).
So, we precalculate prefix and suffix gcd arrays.
If we have:
Prefixi = GCD of A1, A2 ... Ai
Suffixi = GCD of AN, AN-1 ... Ai
answer to query [L, R], would be GCD of PrefixL-1 and SuffixR+1.

We can calculate prefix and suffix arrays in O(N) if we notice that:
Prefixi = GCD(Prefixi-1, Ai)
Suffixi = GCD(Suffixi+1, Ai)

Pseudo Code for building prefix and suffix arrays:

n,a=input
pre[n],suf[n]

//base case
pre[1]=a[1]
suf[n]=a[n]

for i=2 to n:
    pre[i] = gcd(pre[i-1], a[i])

for i=n-1 to 1:
    suf[i] = gcd(suf[i+1], a[i])

So, overall complexity would be O((N + Q) * K), where K is a constant factor for gcd calculation.

ALTERNATIVE SOLUTION:

Use segment trees for range gcd queries. But note that a factor of log N will be increased in complexity.

SOLUTIONS:

Setter's solution
Tester's solution

ONEKING - Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Snigdha Chanda
Tester:Shiplu Hawlader
Editorialist:Lalit Kundu

DIFFICULTY:

EASY-MEDIUM

PRE-REQUISITES:

Greedy

PROBLEM:

Given N (≤100000) intervals [Ai, Bi], one such interval can be deleted by placing a bomb at x if Ai≤ x ≤ Bi. Find minimum number of bombs required to delete all intervals.

EXPLANATION:

First we sort all intervals according to increasing Bi.
Now, let's say we have placed a bomb at position x on the line. All intervals such that their starting point Ai≤ x will get destroyed. So we'll greedily place the bombs when required.

Pseudo code:

n,a,b = input
ar=[]    //ar[i] denotes maximum starting point for intervals ending at i

for i=1 to N:
    ar[b[i]]=max(ar[b[i]], a[i])

ans=0
max=-1  //denotes the latest value of x where we placed a bomb

for i=0 to 2000:
    //we need a bomb to all intervals ending at i'th position
    if max < ar[i]:
        ans += 1
        max = i
print ans

Complexity: O(N+2000).

SOLUTIONS:

Setter's solution
Tester's solution

algorithm of pouring water.

$
0
0

http://www.codechef.com/problems/POUR1

this is a question i found while solving problems from pratice arena on codechef. I saw many solutions but could not understand the logic. On some of the posts i found that DIOPHANTUS has given the solution for this, but could not get any relevant material. Further, the editorial of this question is not provided. please help me in understanding this problem.


Editorial -- FRUITS

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Sunny Aggarwal
Tester:Vasya Antoniuk
Editorialist:Pushkar Mishra

DIFFICULTY:

Cakewalk

PREREQUISITES:

Ad-hoc

PROBLEM:

Given are the number of apples ($N$) and oranges($M$) and $k$, i.e., the amount of money that chef has to buy apples/oranges. Each orange/apple costs 1 unit. What is the minimum difference that can be achieved.

EXPLANATION:

The problem is a very direct one. We have to minimize the difference. We can only increase the number of apples or oranges that we have. The logical step is to increase that commodity which is less because increasing the which is already more will only increase the the difference. Let $minC$ denote the quantity which is less. Let $maxC$ be the quantity which is more. The answer is given by:

$ans = maxC - min(minC+k, maxC)$

We have a min operation in the second term because the optimal case is to make both the quantities equal. If we have enough money to increase the lesser one to more than the other one, then we would rather make them equal so as to have a difference of zero, which is optimal.

COMPLEXITY:

$\mathcal{O}(1)$ per test case.

SAMPLE SOLUTIONS:

Author
Tester
Editorialist

CHEFARRP -- Editorial

$
0
0

PROBLEM LINK:

Practice
Contest

Author:Misha Chorniy
Tester:Jingbo Shang
Editorialist:Pushkar Mishra

DIFFICULTY:

Simple

PREREQUISITES:

None

PROBLEM:

Given an array, we have to report the number of subarrays such that the product of all numbers in that subarray is equal to the sum of all numbers in that subarray.

EXPLANATION:

The problem is very direct given the size of the input array. Since $n \leq$ 50, we can directly iterate over the subarrays and calculate product and sum. The editorialist's solution is very clear in describing the approach. Below is the pseudo-code of the same:

function get_ans(input_array[n])
{
    int count = 0;
    for(i = 1 to n)
    {
        int sum = 0, product = 1;

        for(j = i down_to 1)
        {
            //considering all subarrays ending at i.

            sum = sum + input_array[j];
            product = product*input_array[j];

            if(sum == product)
                count = count+1;
        }
    }

    return count;
}

COMPLEXITY:

$\mathcal{O}(n^2)$ per test case.

SAMPLE SOLUTIONS:

Author
Tester
Editorialist

SUBINC - Editorial

$
0
0

Problem Link

Practice
Contest

Difficulty

Simple

Pre-requisites

Simple dynamic programming

Problem

Count the number of non-decreasing subarrays of the given array A[].

How to get 20 points

Let's choose the left bound, say L. After the left bound is fixed, let's choose the right bound, say R. And now, let's check that the subarray A[L, R] is non-decreasing.

In other words, let's iterate through all possible subarrays and then, for each of them, check whether it is a non-descreasing one or not.

Choosing the left bound takes O(N) operations, choosing the right bound takes O(N) operations too, and checking subarray also takes O(N) operations. Since these operations are nested, hence the total complexity will be O(N3).

This solution is good enough to solve the first subtask.

How to get 50 points

Let's choose the left bound, say L. Let the right bound, say R, be equal to L initially. Then while the elements are non-decreasing keep increasing the right bound R. At some moment, you will certainly stop. The amount of non-decreasing subarrays with the left bound at L will be equal to R-L+1 for every fixed L. The sum of all this values is the answer to the problem.

Choosing the left bound takes O(N) operations, and finding the right bound takes O(N) operations. Since these operations are nested, the complexity of the whole solution will be O(N2).

This solution solves the first and the second subtask, but is still not good enough to get the full points.

How to get 100 points

Let's introduce an array B[] of N elements, where the ith element of B[] defines the amount of the correct subarrays with the right bound equal to i.

Now, let's give the rules for calculating the ith element of B[]:

  • if A[i-1] ≤ A[i], then B[i] = B[i-1] + 1 since every non-decreasing subarray that ends at the (i-1)th element can be continued with the ith element without loss of non-decreasingness and one more non-decreasing subarray that ends at the ith element is A[i, i].
  • if A[i-1] > A[i], then B[i] = 1 since any subarray that ends at the (i-1)th element will lose its' non-decreasingness if continued with the ith element, so the only suitable subarray will be A[i, i].

So, the answer will be equal to the sum of all elements of B[]. The complexity is O(N), because the computation of the array B turns out to be a single for-loop with a condition for the computation of B[i] inside.

Setter's Solution

Can be found here

Tester's Solution

Can be found here

Can't submit solutions to other problems when a contest is running?

$
0
0

Can't we submit solutions to other problems in the practice section when the long challenge is running? I get a message saying "The contest to which this problem belongs is not running. And hence you cannot make a submission for it". Does this mean that the practice section is disabled for 10 days every month?

Have problem with ide

$
0
0

My program runs sucessfully and gives correct output in my pc. But the same code gives wrong answers in codechef's ide. I use the same gcc compiler. Why does this happen?

Viewing all 40121 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>