#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <thread>
#include <vector>
long long parallel_sum(const std::vector<int>& values,std::size_t p) {
    if(p==0 || p>64) throw std::invalid_argument("workers");
    const auto n=values.size(),q=n/p,r=n%p;
    std::vector<long long> partial(p,0);std::vector<std::thread> workers;workers.reserve(p);
    struct JoinAll {
        std::vector<std::thread>& threads;
        ~JoinAll() {for(auto& t:threads) if(t.joinable()) t.join();}
    } join_all{workers};
    for(std::size_t t=0;t<p;++t) {
        const auto begin=t*q+std::min(t,r),end=begin+q+(t<r?1:0);
        workers.emplace_back([&,t,begin,end]{
            long long local=0;for(auto i=begin;i<end;++i) local+=values[i];partial[t]=local;
        });
    }
    for(auto& worker:workers) worker.join();
    return std::accumulate(partial.begin(),partial.end(),0LL);
}
int main() {
    int cases=0;
    for(std::size_t n: {0U,1U,2U,3U,7U,31U,1000U}) for(std::size_t p=1;p<=6;++p) {
        std::vector<int> v(n);for(std::size_t i=0;i<n;++i) v[i]=static_cast<int>(i%17)-8;
        if(parallel_sum(v,p)!=std::accumulate(v.begin(),v.end(),0LL)) throw std::runtime_error("oracle");
        ++cases;
    }
    const auto result=parallel_sum({1,2,3,4,5,6,7,8,9,10},3);
    if(result!=55) throw std::runtime_error("example");
    std::cout<<"sum="<<result<<" cases="<<cases<<'\n';
}
