Basecamp
    Home
    Problems
    Contests
    Courses
    Rating
    Posts
    Store
    Discord
Educational Round #10 — Editorial
Sign in
Tutorial•11 hours ago

Educational Round #10 — Editorial

Eolymp #8684. Sum and amount

A sequence of integers is given. Find the number of integers in the sequence and their sum.

Input. One single line contains a sequence of integers, each does not exceed 100 in absolute value.

Output. Print two numbers in one line: the number of elements in the sequence and their sum.

Sample input
1 2 3 4 5
Sample output
5 15
Open problem
Solution

Read the input sequence of numbers until the end of the file. Then, count the number of integers and compute their sum.

Algorithm implementation

Read the input sequence of numbers until the end of the file. The variable c stores the count of numbers, and the variable s stores their sum.

c = s = 0;
while (scanf("%d", &x) == 1)
{
  c++; 
  s = s + x;
}

Print the count of numbers and their sum.

printf("%d %d\n", c, s);
Eolymp #8877. Perfect square

Positive integer n is given. If n is a perfect square of some positive integer m, print m. Otherwise, print "No".

Input. One positive integer n.

Output. Print the required answer.

Sample input 1
25
Sample output 1
5
Sample input 2
27
Sample output 2
No
Open problem
Solution

Let a=⌊n​⌋. If a⋅a=n, then n is a perfect square.

Example

Let n=27. Then a=⌊27​⌋=5. Check: 5⋅5=27. Therefore, the number 27 is not a perfect square.

Algorithm implementation

Read the input number n.

scanf("%d", &n);

Compute a=⌊n​⌋.

a = (int)sqrt(n);

If a⋅a=n, then the number n is a perfect square.

if (a * a == n) printf("%d\n", a);
else puts("No");
Eolymp #11271. Sum of squares Cnk

Given a non-negative integer n, find the sum of binomial coefficients

(Cn0​)2+(Cn1​)2+(Cn2​)2+...+(Cnn​)2

Input. One non-negative integer n (n≤30).

Output. Print the value of the sum.

Sample input
3
Sample output
20
Open problem
Solution

Let us consider 2n objects a1​,...,a2n​ and find the number of ways to choose n objects from these 2n.

Divide the set into two parts of n objects each:

{a1​,a2​,...,an​} and {an+1​,...,a2n​}

To choose n objects from the 2n, we can select k (k≤n) objects from the left half and n−k objects from the right half.

According to the multiplication principle, the number of ways to make such a selection is

Cnk​⋅Cnn−k​=(Cnk​)2

Since k can take all values from 0 to n, the sum of all possibilities is

k=0∑n​(Cnk​)2,

which equals the number of ways to choose n objects from 2n, that is C2nn​. Thus, we obtain the formula:

(Cn0​)2+(Cn1​)2+(Cn2​)2+...+(Cnn​)2=C2nn​

Example

For n=3 the answer is (C30​)2+(C31​)2+(C32​)2+(C33​)2=12+32+32+12=20

At the same time C63​=3!⋅3!6!​=64⋅5⋅6​=20.

Algorithm implementation

The function Cnk computes the value of the binomial coefficient Cnk​.

long long Cnk(long long n, long long k)
{
  long long res = 1;
  if (k > n - k) k = n - k;
  for (long long i = 1; i <= k; i++)
    res = res * (n - i + 1) / i;
  return res;
}
C++
8 lines
185 bytes

The main part of the program. Read the value of n.

scanf("%lld", &n);

Compute and print the answer.

res = Cnk(2*n, n);
printf("%lld\n", res);
Eolymp #1083. Sequence

Given a numerical sequence a1​,a2​,a3​,…, the first term is known, and each subsequent term is calculated using the following formula:

ai​=(ai−1​⋅ai−1​)mod10000.

Find the n-th term of this sequence.

Input. The first line contains two integers: a1​ and n (0≤a1​≤10000, 1≤n≤2000000010).

Output. Print one integer an​.

Sample input
4 3
Sample output
256
Open problem
Solution

Let us express the first terms of the sequence in terms of a1​:

  • a2​=a12​ mod 10000,

  • a3​=a22​ mod 10000=a14​ mod 10000,

  • a4​=a32​ mod 10000=a24​ mod 10000=a18​ mod 10000

Thus, the formula can be written as:

ai​=ai−12​ mod 10000

Which means that to compute an​, it is enough to raise a1​ to the power of 2n−1 modulo 10000:

an​=a12n−1​ mod 10000

Taking into account the modular exponentiation identity:

ab mod n=ab mod ϕ(n) mod n,

we proceed as follows to find the result res:

  • Compute x=2n−1 mod ϕ(10000)=2n−1 mod 4000,

  • Then compute res=a1x​ mod 10000

Algorithm implementation

The function PowMod computes the value of xn mod m.

int PowMod(int x, int n, int m)
{
  if (n == 0) return 1;
  if (n % 2 == 0) return PowMod((x * x) % m, n / 2, m);
  return (x * PowMod(x, n - 1, m)) % m;
}

Read the input data.

scanf("%d %d",&a,&n);

Compute x=2n−1 mod 4000. And after that, compute and print the final answer:

res=ax mod 10000
x = PowMod(2,n-1,4000);
res = PowMod(a,x,10000);
printf("%d\n",res);
Eolymp #4416. Testing System

Young programmer Sasha wrote his first testing system. He was so excited that it successfully compiled that he decided to invite his school friends to his own contest.

However, at the end of the round, it turned out that the system could not sort the teams in the results table. Help Sasha implement this sorting.

Teams are ordered according to ICPC rules:

  • By the number of solved problems in descending order;

  • If the number of solved problems is the same, sort by penalty time in ascending order;

  • If all the previous criteria are equal, sort by team number in ascending order.

Input. The first line contains the number of teams n (1≤n≤105) participating in the contest. In the i-th of the following n lines, the number of solved problems s (0≤s≤100) and the penalty time t (0≤t≤105) for the team with number i are given.

Output. Print n integers — the team numbers in sorted order.

Sample input
5
3 50
5 720
1 7
0 0
8 500
Sample output
5 2 1 3 4
Open problem
Solution

We'll represent a team as a structure containing the following fields:

  • team number;

  • penalty time;

  • number of solved problems;

To solve the problem, it is necessary to implement a comparator — a function that compares two teams according to the ICPC rules, and then perform the sorting.

Algorithm implementation

Declare a team structure — an ICPC competition participant, including the team number, penalty time, and number of solved problems.

struct person
{
  int id, penalty_time, problems;
} *acm;

Implement the function cmp — a comparator for sorting the competition participants.

int cmp(person a, person b)
{

Sort by the number of solved problems in descending order.

  if (a.problems != b.problems) return a.problems > b.problems;

If the number of solved problems is equal, sort by penalty time in ascending order.

  if (a.penalty_time != b.penalty_time) 
    return a.penalty_time < b.penalty_time;

If all previous criteria are equal, sort by team number in ascending order.

  return a.id < b.id;
}

The main part of the program. Allocate memory for the array of teams.

scanf("%d",&n);
acm = new person[n];

Read the data about the teams.

for (i = 0; i < n; i++)
{
  scanf("%d %d",&acm[i].problems,&acm[i].penalty_time);
  acm[i].id = i + 1;
}

Sort the teams according to the given conditions.

sort(acm,acm+n,cmp);

Print the team numbers in the order of their placement in the results table.

for (i = 0; i < n; i++)
  printf("%d",acm[i].id);
printf("\n");

delete[] acm;

Algorithm implementation — vector

Declare a team structure — an ICPC competition participant, including the team number, penalty time, and number of solved problems.

struct person
{
  int id, penalty_time, problems;
};

Declare an array of teams acm.

vector<person> acm;

Implement the function cmp — a comparator for sorting the competition participants.

int cmp(person a, person b)
{

Sort by the number of solved problems in descending order.

  if (a.problems != b.problems) return a.problems > b.problems;

If the number of solved problems is equal, sort by penalty time in ascending order.

  if (a.penalty_time != b.penalty_time) 
    return a.penalty_time < b.penalty_time;

If all previous criteria are equal, sort by team number in ascending order.

  return a.id < b.id;
}

The main part of the program. Read the input data.

scanf("%d",&n);
acm.resize(n);
for (i = 0; i < n; i++)
{
  scanf("%d %d",&acm[i].problems,&acm[i].penalty_time);
  acm[i].id = i + 1;
}
C++
7 lines
143 bytes

Sort the teams according to the given conditions.

sort(acm.begin(),acm.end(),cmp);

Print the team numbers in the order of their placement in the results table.

for (i = 0; i < n; i++)
  printf("%d ",acm[i].id);
printf("\n");

Algorithm implementation — build-in comparator

#include <cstdio>
#include <algorithm>
using namespace std;

int n, i, ptr;
struct person
{
  int id, penalty_time, problems;
  int operator< (const person &a) const
  {
    if (problems != a.problems) return problems > a.problems;
    if (penalty_time != a.penalty_time)
      return penalty_time < a.penalty_time;
    return id < a.id;
  }
} *acm;

int main(void)
{
  scanf("%d",&n);
  acm = new person[n];

  for (i = 0; i < n; i++)
  {
    scanf("%d %d",&acm[i].problems,&acm[i].penalty_time);
    acm[i].id = i + 1;
  }

  sort(acm,acm+n);
  
  for (i = 0; i < n; i++)
    printf("%d ",acm[i].id);
  printf("\n");
  delete[] acm;
  return 0;
}
C++
36 lines
685 bytes
Eolymp #5730. YAPTCHA

The Faculty of Mathematics encountered a problem. Due to the large number of automated programs browsing their web pages, it was decided to restrict access to their scientific articles.

To gain access, one must now demonstrate their knowledge — namely, solve a mathematical problem.

However, the test turned out to be too difficult not only for graduate students, but even for some professors. Therefore, the faculty needs to develop a program that automatically solves this problem.

Visitors to the main page of the Faculty of Mathematics are given the following task: for a given positive integer n, compute the value

Sn​=k=1∑n​⌊3k+7(3k+6)!+1​−⌊3k+7(3k+6)!​⌋⌋,

where ⌊x⌋ denotes the greatest integer less than or equal to x.

Input. The first line contains the number of queries t (t≤106).

Each of the following t lines contains one integer n (1≤n≤106).

Output. For each query, print the value of Sn​ on a separate line.

Sample input
13
1
2
3
4
5
6
7
8
9
10
100
1000
10000
14 lines
53 bytes
Sample output
0
1
1
2
2
2
2
3
3
4
28
207
1609
13 lines
45 bytes
Open problem
Solution

Let m=3k+7. Then the given expression can be rewritten in the form:

Sn​=m=10,m=1 (mod 3)∑3n+7​⌊m(m−1)!+1​−⌊m(m−1)!​⌋⌋,

Wilson's Theorem. If m is a prime number, then

(m−1)!=−1 (mod m)

That is,

(m−1)!+1=0 (mod m)

Therefore, if m is prime, the number m(m−1)!+1​ is an integer.

At the same time,

⌊m(m−1)!​⌋=⌊m(m−1)!+1​−m1​⌋=m(m−1)!+1​−1

Then the entire expression equals

⌊m(m−1)!+1​−⌊m(m−1)!​⌋⌋=m(m−1)!+1​−(m(m−1)!+1​−1)=1

If m is a composite number, then

(m−1)!=0 (mod m),

because among its factors there are all the divisors of m.

In this case, the number

m(m−1)!​

is an integer.

Then the entire expression equals

⌊m(m−1)!+1​−⌊m(m−1)!​⌋⌋=⌊m(m−1)!​+m1​−m(m−1)!​⌋=⌊m1​⌋=0

Therefore, to compute Sn​, it is enough to count the number of prime numbers of the form 3k+7 for 1≤k≤n.

Using the Sieve of Eratosthenes, we build the array used, where:

used[i]={1,0,​if i is prime,if i is composite.​

Then, using the array used, construct the array a, which stores information about prime numbers of the form 3i+7:

a[i]={1,0,​if 3i+7 is prime,if 3i+7 is composite.​

Now

Sn​=a[1]+a[2]+…+a[n]

Since the problem contains many test cases, to answer each in constant time, we build the prefix sums:

p[i]=a[1]+a[2]+…+a[i]

Now, to solve the problem for any given value of n, it is enough to print p[n].

Example

Let m=7 be a prime number. Then

⌊76!+1​−⌊76!​⌋⌋=⌊7721​−⌊7720​⌋⌋=⌊103−⌊10276​⌋⌋=⌊103−102⌋=1

Let m=6 be a composite number. Then

⌊65!+1​−⌊65!​⌋⌋=⌊6121​−⌊6120​⌋⌋=⌊20+61​−20⌋=⌊61​⌋=0

Let's compute the answer for n=10. Consider all numbers of the form 3k+7, where 1≤k≤10. Among them, identify the prime numbers.

Among the listed numbers, there are 4 prime numbers: 13,19,31 and 37. Therefore, S10​=4.

Algorithm implementation

Let us declare the arrays. Since n≤106, the size of the arrays should be set to 3n+7=3⋅106+7.

#define MAX 3000010
char used[MAX], a[MAX];

The function Init implements the Sieve of Eratosthenes. The array used stores information about prime numbers:

used[i]={1,0,​if i is prime,if i is composite.​

The array a stores information about prime numbers of the form 3i+7:

a[i]={1,0,​if 3i+7 is prime,if 3i+7 is composite.​
void Init()
{
  for (int i = 2; i < MAX; i++)
  {
    if (!used[i])
    {
      if ((i - 7) % 3 == 0)
        a[(i - 7) / 3] = true;
      if (i < sqrt(MAX))
        for (int j = i * i; j < MAX; j += i)
          used[j] = true;
    }
  }
}
C++
14 lines
255 bytes

The main part of the program. Fill the arrays.

Init();

Compute the prefix sums for the array a:

p[i]=a1​+a2​+...+ai​
for (int i = 2; i < MAX; ++i)
  p[i] = p[i - 1] + a[i];

Process the tests sequentially.

scanf("%d", &tests);
while (tests--)
{
  scanf("%d", &n);

For each value of n print p[n].

  printf("%d\n", p[n]);
}
Eolymp #7757. Square

Jian-Jia has a piece of metal material and wants to cut a square from it. The material is represented as an n×n grid, and cuts can only be made along the grid boundaries.

Each cell of the grid is either usable or defective. Jian-Jia aims to cut the largest possible square that contains no defective cells. After determining the maximum possible size of such a square, he also wants to know how many different ways this square can be cut from the material.

Finally, Jian-Jia reports the product of the maximum size and the number of such possible ways.

Consider a 6×6 material, as shown in the figure below. The black cells are defective. The largest square that can be cut has size 3×3, and there are two possible ways to obtain it (shown as the red and green squares). Therefore, Jian-Jia reports the product 3⋅2=6.

Your task is to determine the maximum size of a square that can be cut from the given material, as well as the number of distinct ways to obtain such a square. Output the product of these two values.

Input. The first line contains one integer n (1≤n≤1000) — the size of the material.

Each of the next n lines contains n integers. A value of 1 indicates that the corresponding cell is usable, while 0 indicates that it is defective.

Output. Print one integer — the product of the size of the largest square without defective cells and the number of its possible positions in the material.

Sample input 1
6
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
7 lines
81 bytes
Sample output 1
18
Sample input 2
6
0 1 1 1 1 0
1 0 1 1 1 1
0 1 1 1 1 1
1 1 0 1 1 1
1 1 1 1 0 1
1 1 0 1 1 1
7 lines
81 bytes
Sample output 2
6
Open problem
Solution

Let us define a two-dimensional array dp, where

  • dp[i][j] denotes the side length of the largest square consisting entirely of ones, with its bottom-right corner at cell (i,j).

Let the array m represent the given grid.

Base cases

  • If m[i][j]=0 (the cell is defective), then no square can end at cell (i,j). Therefore, dp[i][j]=0;

  • If the cell lies on the boundary (i=0 or j=0) and m[i][j]=1, then only a square of size 1 is possible. Therefore, dp[i][j]=1

DP transitions

Assume that m[i][j]=1. Consider the following cases:

  1. Suppose that m[i−1][j]=m[i][j−1]=k. Then the value of dp[i][j] depends on the state of the cell m[i−k][j−k]:

    • If m[i−k][j−k]=1, then the entire square with corners at (i−k,j−k) and (i,j) consists only of ones, so dp[i][j]=k+1.

    • If m[i−k][j−k]=0, then the square cannot be extended, and dp[i][j]=k.

  2. If m[i−1][j]=m[i][j−1], then the value of dp[i][j] is determined as

dp[i][j]=min(dp[i−1][j],dp[i][j−1])+1

Summarizing the above, we obtain the general formula:

dp[i][j]=min(dp[i−1][j],dp[i][j−1],dp[i−1][j−1])+1

Example

Consider the second test case. Let us construct the dp array for it.

There are two largest squares of size 3⋅3. The product of the maximum square size and the number of its occurrences is 3⋅2=6.

Algorithm implementation

Declare the array dp.

#define MAX 1010
int dp[MAX][MAX];

Read the value of n. The variable size stores the side length of the largest square, while cnt stores the number of such squares in the given grid. Initialize the dp array with zeros.

scanf("%d", &n);
memset(dp,0,sizeof(dp));
size = cnt = 0;

Iterate over the elements of the dp array row by row: rows in increasing order, and within each row, columns also in increasing order.

  for(i = 1; i <= n; i++)
  for(j = 1; j <= n; j++)
  {
    scanf("%d",&val);

Assume that all values of the dp array up to cell (i,j) have already been computed. Read the next value val=m[i][j]. The input matrix is not stored entirely in memory; instead, it is processed on the fly.

Since the dp array is initially initialized with zeros, when val=0, the value dp[i][j] automatically remains zero.

    if (val == 1)
    {
      dp[i][j] = min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1]) + 1;

Update the values of size and cnt based on the current square of size dp[i][j].

      if (dp[i][j] == size) cnt++;
      if (dp[i][j] > size) {size = dp[i][j]; cnt = 1;}
    }
  }

Print the answer.

printf("%lld\n",1LL * size * cnt);
Eolymp #6828. Bread Sorting

Michael works in a bakery. At the end of each shift, his boss asks him to sort the loaves of bread in a certain order. However, she cannot decide exactly what that order should be — according to Michael's observations, it seems to be different every day.

Michael has been working at the bakery for some time and has learned a clever trick with his wooden bread paddle. He can scoop up three adjacent loaves with the paddle and toss them into the air so that when they land, the rightmost loaf moves to the leftmost position, while the other two loaves shift one position to the right. In other words, he can perform a cyclic right rotation on any subsequence of three consecutive loaves.

Before the end of the shift, his colleagues have already placed the bread in one long line. Michael wants to sort the loaves using his paddle trick. He can pick up any three consecutive loaves in the line, rotate them as described, and put them back. However, sometimes it does not matter how many times he uses the paddle — sorting the bread into the order required by his boss may simply be impossible.

Input. The first line contains an integer n (3≤n≤105). Then two lines follow:

  • the first line contains a permutation of the integers from 1 to n, representing the current order of the loaves.

  • the second line contains a permutation of the integers from 1 to n, representing the order of the loaves required by the boss.

Output. Print "Possible" if Michael can use his paddle to sort the loaves into the order required by his boss. Otherwise, print "Impossible".

Sample input 1
4
1 3 4 2
4 3 2 1
Sample output 1
Possible
Sample input 2
6
1 2 3 4 5 6
6 5 4 3 2 1
Sample output 2
Impossible
Open problem
Solution

The paddle trick performs the following permutation of the loaves:

(ac​ba​cb​)

It can be represented as two swaps of adjacent elements:

(a,b,c)→(a,c,b)→(c,a,b)

Each swap of adjacent elements changes the parity of the permutation. Therefore, this operation on the loaves preserves the parity of the permutation.

It is possible to sort the loaves in the order required by Michael's boss only if the parities of the permutations coincide.

A linear solution to the problem is based on the fact that two permutations have the same parity if and only if the parity of the number of cycles in their decompositions is the same.

Lemma. Consider the following fact from permutation theory:

parity of a permutation=(n−number of cycles) mod 2

Therefore, to check the parity one can:

  • decompose the permutation into cycles;

  • count the number of cycles.

If two permutations have the same parity of the number of cycles, then their permutation parities coincide.

Intuitively, this follows from the fact that each cycle of length k can be constructed from k−1 swaps of elements; therefore, the total number of swaps is equal to

n−number of cycles

Example

In the first example, the first permutation contains 2 inversions, while the second contains 6 inversions. The number of inversions in both permutations has the same parity.

Let us decompose the permutations into cycles:

  • (1,3,4,2)=(1)(3,4,2);

  • (4,3,2,1)=(4,1)(3,2);

Both permutations consist of two cycles; therefore, the number of cycles in them also has the same parity.

In the second example, the first permutation contains 0 inversions, while the second contains 15 inversions. The number of inversions in these permutations has different parity.

Let us decompose the permutations into cycles:

  • (1,2,3,4,5,6)=(1)(2)(3)(4)(5)(6);

  • (6,5,4,3,2,1)=(6,1)(5,2)(4,3);

The first permutation consists of 6 cycles, while the second consists of 3 cycles. Thus, the parity of the number of cycles in these permutations is different.

Algorithm implementation

Declare an array to store the permutation.

#define MAX 100010
int a[MAX];

The function run traverses one cycle of the permutation starting from index pos. At each step, it moves to the next element of the cycle according to the rule pos→a[pos]. Visited elements are marked with the value −1 to avoid processing them again. Thus, the function completely traverses one cycle of the permutation and marks all its elements as already visited.

void run(int pos)
{
  int v;
  while (a[pos] != -1)
  {
    v = a[pos];
    a[pos] = -1;
    pos = v;
  }
}
C++
10 lines
118 bytes

The function parity computes the parity of the number of cycles in the permutation a, that is, it returns the number of cycles modulo 2. The function sequentially scans all positions of the array.

int parity(int *a)
{
  int res = 0;

Sequentially examine all positions of the array.

  for (int i = 0; i < n; i++)

If an element has not yet been visited (a[i]=−1), this means the beginning of a new cycle. In this case, the function run(i) is called, which traverses the entire cycle and marks its elements with the value −1.

    if (a[i] != -1) 
    {
      run(i);

After traversing the cycle, the counter res is increased by 1.

      res++;
    }

Return the parity of the number of cycles.

  return res % 2;
}

The main part of the program. Read the first permutation. During input, each value is decreased by 1 (a[i]−−) to convert from 1-based indexing (1..n) to the more convenient 0-based indexing (0..n−1).

scanf("%d",&n);
for (i = 0; i < n; i++)
  scanf("%d",&a[i]), a[i]--;

In the variable p1, compute the parity of the number of cycles in the permutation a.

p1 = parity(a);

Read the second permutation. In the variable p2, compute the parity of the number of cycles in the permutation a.

for (i = 0; i < n; i++)
  scanf("%d",&a[i]), a[i]--;
p2 = parity(a);

Compare the parities of the number of cycles in the two permutations and print the result.

if (p1 == p2) printf("Possible\n");
else printf("Impossible\n");
Eolymp #2299. Theodore Roosevelt

"Theodore Roosevelt" — the flagship of the Kukuland fleet. The sworn enemies of Kukuland, the Flat-Earthers, decided to destroy it. They learned that "Theodore Roosevelt" is represented by a convex polygon with n vertices, and the coordinates of all its vertices are known to them. Then they launched m ballistic missiles and recorded the coordinates of their explosion points. According to the calculations of the Flat-Earthers' headquarters, "Theodore Roosevelt" will be destroyed if at least k missiles hit it. Determine whether the Flat-Earthers managed to destroy the ship.

Input. The first line contains integers n,m and k (3≤n≤105,0≤k≤m≤105). The next n lines contain the coordinates of the polygon vertices in counterclockwise order. The following m lines contain the coordinates of the explosion points. All coordinates are integers with absolute values not exceeding 109.

Output. Print "YES" if at least k points lie inside the polygon, and "NO" otherwise.

Sample input
5 4 2
1 -1
1 2
0 4
-1 2
-1 -1
-2 -1
1 -1
0 1
2 3
10 lines
59 bytes
Sample output
YES
Open problem
Solution

Consider the problem of determining whether a point belongs to a convex polygon.

Suppose the vertices of the polygon are given in counterclockwise order: p1​,p2​,...,pn​. Fix the vertex p1​. Then all other vertices are ordered around it by polar angle.

Draw rays from point p1​ through the remaining vertices (i.e., the diagonals of the polygon). We can now apply binary search to find an edge pi​pi+1​ such that the orientations of the triples of points p1​pi​q and p1​pi+1​q are different.

Thus, we determine the sector (triangle) in which the point q may lie.

After the angle pi​p1​pi+1​ containing the point q is found, we can check in constant time whether the points p1​ and q lie on the same side of the line pi​pi+1​. For this, the orientation of the triple pi​pi+1​q must be left (since the orientation of pi​pi+1​p1​ is left, as the polygon vertices are given in counterclockwise order).

At the beginning of the algorithm, it is also necessary to check boundary cases: if the orientation of the triple p1​pn​q is left or the orientation of the triple p1​p2​q is right, then the point q lies outside the polygon.

Turn direction. Consider moving from point А to point В, and then from В to point С. The turn is considered left (counterclockwise) if the vector (pseudo-scalar) product AB×BC>0, and right if AB×BC<0.

Algorithm implementation

Let us define a Point structure and an array of points.

#define MAX 100001
struct Point
{
  long long x, y;
  Point(long long x = 0, long long y = 0) : x(x), y(y) {}
};
Point p[MAX];
C++
7 lines
134 bytes

The function angle determines whether the turn made when moving through points А,B,С is left or right. To do this, we calculate the corresponding vectors:

AB=(b.x−a.x,b.y−a.y)BC=(c.x−b.x,c.y−b.y)

The pseudo-scalar (cross) product of AB×BC is

​b.x−a.xc.x−b.x​b.y−a.yc.y−b.y​​=(b.x−a.x)⋅(c.y−b.y)−(b.y−a.y)⋅(c.x−b.x)

The sign of this expression determines the direction of the turn:

  • Positive value — left turn;

  • Negative value — right turn;

int angle(Point a, Point b, Point c)
{
  long long q = (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
  return (q > 0) - (q < 0); // sgn(q)
}

The function inside returns true if the point q lies inside the polygon.

bool inside(Point q)
{

We choose the first vertex of the polygon as the base.

  Point a = p[1];

If the orientation of the triple p1​pn​q is left, or the orientation of the triple p1​p2​q is right, then the point q lies outside the angle pn​p1​p2​, and therefore outside the polygon.

  if (angle(a, p[2], q) < 0 || angle(a, p[n], q) > 0) return false;

Perform a binary search on the interval [l;r]=[2;n]. We look for points pl​ and pr​ (r=l+1) such that the point q lies inside the angle pl​p1​pr​.

  int l = 2, r = n, m;
  while (l + 1 < r)
  {
    m = (l + r) / 2;
    if (angle(a, p[m], q) < 0)
      r = m;
    else
      l = m;
  }
  return angle(p[l], p[r], q) >= 0;
}
C++
11 lines
187 bytes

The main part of the program. Read the input data.

scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++)
{
  scanf("%lld %lld", &x, &y);
  p[i] = Point(x, y);
}

Compute the number of points that lie inside the polygon.

res = 0;
for (int i = 1; i <= m; ++i)
{
  scanf("%lld %lld", &x, &y);
  if (inside(Point(x, y))) res++;
}

Print the answer.

if (res < k) puts("NO"); else puts("YES");
Eolymp #7747. City Horizon

Farmer John has arrived in the city with his cows! During sunset, the cows look at the city skyline and observe beautiful silhouettes formed by rectangular buildings.

The entire skyline is represented by a number line with n buildings. The silhouette of the i-th building extends along the horizon between points ai​ and bi​ and has height hi​. Determine the total area (in square units) of the silhouette formed by all n buildings.

Input. The first line contains an integer n (1≤n≤40000). Each of the next n lines describes the i-th building with three integers: ai​,bi​ (1≤ai​<bi​≤109) and hi​ (1≤hi​≤109).

Output. Print the total area of the city skyline (in square units) formed by all n buildings.

Sample input
4
2 5 1
9 10 4
6 8 2
4 6 3
Sample output
16
Open problem
Solution

Consider all points — the x-coordinates of the beginnings and ends of the buildings — and sort them in increasing order. For each such point, we store:

  • its coordinate,

  • its type (start of a building — type=0, end — type=1),

  • the height of the corresponding building.

Next, process these points sequentially from left to right.

We maintain a multiset s that stores the heights of buildings that have already started but have not yet ended at the current moment. This multiset allows us to efficiently determine the maximum height among the active buildings.

Let the current point have coordinate xi​, and the next point xi+1​. Let h denote the maximum element in the multiset s (if the set is empty, assume h=0). Then, on the interval [xi​,xi+1​]), the maximum height of the silhouette is h, and the contribution to the area is

(xi+1​−xi​)⋅h

Add this value to the total area.

After that, update the multiset:

  • if the point xi​ is the start of a building, insert its height into s;

  • if it is the end of a building, we remove the corresponding height from s.

The order of processing events with the same x-coordinate (starts and ends of buildings) does not affect the correctness of the solution, since segments of zero length do not contribute to the area.

Example

Algorithm implementation

To represent a point, we introduce a structure node that stores its x-coordinate, a flag indicating whether it is the start (type=0) or the end (type=1) of a segment, and the height h of the corresponding building.

struct node
{
  int x, type, h;
  node(int x, int type, int h) : x(x), type(type), h(h) {};
};

Define a comparator f for points — sort them in increasing order of their x-coordinates.

int f(node a, node b)
{
  return a.x < b.x;
}

Declare an array of points Event, as well as a multiset s to store the heights of buildings intersecting the current position of the sweep line.

vector<node> Event;
multiset<int, greater<int> > s;

Read the input data. Construct the array of points.

scanf("%d",&n);
for(i = 0; i < n; i++)
{
  scanf("%d %d %d",&left,&right,&height);
  Event.push_back(node(left,0,height));
  Event.push_back(node(right,1,height));
}
C++
7 lines
173 bytes

Sort the array of points in non-decreasing order of their x-coordinates.

sort(Event.begin(),Event.end(),f);

Accumulate the total area of the city skyline in the variable res.

res = 0;

Move from left to right over the points in the Event array. For each index i in the for loop, consider the interval (Event[i].x,Event[i+1].x).

for (i = 0; i < Event.size() - 1; i++)
{

If the point xi​ is the start of a building, insert the corresponding height into the multiset.

  int h = Event[i].h;
  if (Event[i].type == 0) s.insert(h);

If the point xi​ is the end of a building, remove the corresponding height from the multiset.

  else s.erase(s.find(h));

If the multiset is not empty, then on the segment between Event[i].x and Event[i+1].x there exists a skyline whose height is equal to the maximum element in s, i.e. ∗s.begin().

  if (!s.empty())
    res += 1LL * *s.begin() * (Event[i+1].x - Event[i].x);
}

Print the computed area.

printf("%lld\n",res);

1

Comments

Loading

Just a moment, getting data from the server

Nothing yet

Be the first one to start the conversation!
Sign in