#include <iostream>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <thread>
#include <vector>


std::size_t count_needle(int * first, int *const last,
                         int const* needleFirst, int const* const needleLast) {
   std::sort(first, last);
   
   std::size_t count = 0;
   while (first != last && needleFirst != needleLast) {
      if (*first == *needleFirst) {
         ++count;
         ++first;
      } else if (*needleFirst < *first) {
         ++needleFirst;
      } else {
      	++first;
      }
   }
   
   return count;
}


int main()
{
    int arrayFirst[] = { 11, 5, 2, 8, 4, 5, 2, 5, 7, 9, 12, 16, 17, 18, 20 };
    int arraySecond[] = { 22, 5, 8, 3, 2, 9, 4, 3, 9, 10 };
    
    std::sort(std::begin(arraySecond), std::end(arraySecond));
    auto const arraySecondEnd = std::unique(std::begin(arraySecond), std::end(arraySecond));
    
    auto const numThreads = std::thread::hardware_concurrency();
    std::vector<std::thread> tasks;
    tasks.reserve(numThreads);
    std::vector<size_t> results(numThreads);
    
    auto const firstSize  = sizeof(arrayFirst) / sizeof(*arrayFirst); 
    auto const firstStep = (firstSize + numThreads - 1) / numThreads;
    
    for (std::size_t i = 0; i != numThreads; ++i) {
    	auto const firstBegin = arrayFirst + i * firstStep;
    	auto const firstEnd   = arrayFirst + std::min((i + 1) * firstStep, firstSize);
    	
    	std::thread task([=, &results] () {
    		results[i] = count_needle(firstBegin, firstEnd, arraySecond, arraySecondEnd);
    	});
    	tasks.push_back(std::move(task));
    }
    
    for (auto & task : tasks) {
       task.join();
    }
    
    auto const count = std::accumulate(std::begin(results), std::end(results), std::size_t(0));
    
    std::cout << count << std::endl;
}