V
V
Vyacheslav2019-03-28 08:20:56
Programming
Vyacheslav, 2019-03-28 08:20:56

How to solve the problem of blocking addresses?

The task was in the final of this competition.
I cleaned it a little from the husk to make it sound shorter. We could not solve it, and there was no analysis of problems from the organizers. It is obvious that it is not solved in an acceptable time by brute force (I checked :) Can someone tell me which way to look?
Computers connected to the network have their own IP addresses. Each IP address is represented by a natural number from 1 to 2^30.
To block / unblock an IP address, a sequence of commands is sent to the Network in the form of natural numbers from 1 to 999.
How do these commands work?
The “2” command affects every second IP address, blocking or unblocking it, according to the rule: if the IP address was not blocked before this command was executed, then it is blocked, if the IP address was blocked, then it is unblocked.
Command "3 - affects every third IP address, blocking or unblocking it according to the same rule.
Command “4” affects every fourth IP address in the same way,
command “5” affects every fifth one, and so on.
Clearly, the "1" command affects all IP addresses (i.e., "every first IP address"), producing a complete inversion where all blocked IP addresses are unblocked and all non-blocked ones are blocked.
It is necessary to determine from the available sequence of commands how many IP addresses will be blocked after executing all these commands, provided that before that there were no blocked IP addresses on the Network.
Initial data: an array of natural numbers from 1 to 999
Present the RESULT in the following form:
For a sequence of commands: 2 6 8 3
Number of blocked IP addresses 581 610 155

Answer the question

In order to leave comments, you need to log in

1 answer(s)
T
Tabris17, 2019-03-28
@Tabris17

It's clear that you need to count only the sums of changes .
I got something like this formula

spoiler
#include <iostream>
#include <cmath> 

using namespace std;

int GCD(int a, int b) { //наибольший делитель
  return b ? GCD(b, a%b) : a;
}

int LCM(int a, int b) { //наименьшее кратное
  return a / GCD(a, b) * b;
}

int main()
{
    
  int a[4] = { 2, 6, 8, 3}; 
  int k = 0; //счетчик заблокированных
  int n = pow(2, 30);
  int b = 1;
  for (int i = 0; i < 4; i++)
  {
    k += floor(n/a[i]);
    b = -1;
    for (int j = 0; j < i; j++)
    {
      k += floor(n / LCM(a[j], a[i])) *b *2;
      b *= -1;
    }
  }
  cout << "otvet " << k;
}

Added:
if you put 2, 4, 8, 3, and not 2, 3, 4, 8, then it will work correctly
here you still need to think and refine the sign that is placed before 2*(n / LCM (a1, a2))
you need to identify a pattern and correctly specify the degree of y -1

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question