cppAcademy
FROM LEARNING TO COMPETING

Intermediate.
Put your skills to the test.

Bulgarian Informatics Group D · 2007–2026

270 independently explained problems: 54 Municipal, 54 Regional, 105 National Olympiad and 57 Autumn Tournament tasks. Start with the easier tasks and work upwards. Difficulty labels are learning estimates, not official ratings; Group D also includes challenging national-level problems. The six 2017 National tasks shared by Groups C and D use their existing permanent URLs. Years follow Arena’s competition-season labels. Source clarifications and special grader requirements are noted on affected tasks.
GROUP D2022 · MediumDivisor sieve and prefix sums

Abundant-or-Perfect Range Queries

National Olympiad — National round (2022 season)

Submission name: izobilni.cpp

Problem summary

Count numbers in each inclusive interval whose proper-divisor sum is at least the number itself.

Input

Q and Q pairs l r.

Output

One count per query.

Constraints

1≤Q≤100000; 1≤l≤r≤1000000.

Worked example

Input and output for the worked example discussed below.

Input

3
1 10
2 7
10 50

Output

1
1
10

Solution analysis

  1. Sieve divisor sums: for each d add it to2d,3d,… . Starting at2d excludes the number itself.
  2. Build prefix[x]=prefix[x−1]+[sum[x]≥x]. Answer each interval by prefix[r]−prefix[l−1], avoiding repeated divisor work.
  3. Up to10 only6 qualifies since1+2+3=6. The non-strict source definition includes perfect numbers, so both first sample intervals return1.

Why it works

Each proper divisor visits a multiple exactly once. The sieve sums are therefore exact, and prefix subtraction counts qualifying numbers in each interval.

Complexity: O(MlogM+Q) time and O(M) space for M=10^6; O(1) per query.

Watch out. Use≥ rather than>;1 has proper-divisor sum zero and does not qualify.

Commented C++17 solution

An independently written complete program with standard headers.

#include<iostream>
#include<vector>
using namespace std;
// Each proper divisor visits a multiple exactly once.
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    const int limit=1000000;
    vector<int>sum(limit+1,0);
    for(int d=1;d*2<=limit;d++){
        for(int x=d*2;x<=limit;x+=d){
            sum[x]+=d;
        }
    }
    vector<int>prefix(limit+1,0);
    for(int x=1;x<=limit;x++){
        prefix[x]=prefix[x-1]+(sum[x]>=x);
    }
    int q;
    cin>>q;
    while(q--){
        int l,r;
        cin>>l>>r;
        cout<<prefix[r]-prefix[l-1]<<'\n';
    }
}

Source: Arena Olimpiici ↗