Distinct Nearest Differences
National Olympiad — National round
Submission name: mindiff.cpp
Problem summary
Generate A of length N by Ai=(i·L) mod P, then negate its first F entries. Generate B of length M by Bi=(i·R) mod Q, then negate its first G entries. Indices start at one. For every B value find its minimum absolute difference from any A value. Output the distinct resulting differences in descending order.
Input
N L P F on the first line; M R Q G on the second.
Output
Number of distinct differences; then those differences in descending order.
Constraints
1 ≤ N,M ≤ 20000000; 0 ≤ F ≤ N; 0 ≤ G ≤ M; 1 ≤ L,P,R,Q ≤ 4000000.
Worked example
An independently prepared example for this explanation.
Input
3 2 7 0 3 1 5 0
Output
2 1 0
Solution analysis
- All values lie in [−3999999,3999999]. Mark A values in an array over this bounded domain, generating residues incrementally.
- Scan left to right and right to left to compute distance to the nearest marked value for every coordinate.
- Stream B and mark each queried distance; print marked distances descending. The sequences themselves need not be stored.
Why it works
In one dimension, a nearest marked coordinate lies immediately to the left or right. The two scans compute the distance to these possibilities, and their minimum is exact. Streaming B then gives exactly the distinct requested answers.
Watch out. Apply negation after generating the modular residue; negating the recurrence state changes later values incorrectly.
Commented C++17 solution
An independently written complete program with standard headers.
// Key idea: In one dimension, a nearest marked coordinate lies immediately to the left or right. The
// two scans compute the distance to these possibilities, and their minimum is exact.
#include<iostream>
#include<vector>
#include<algorithm>
#include<tuple>
#include<iterator>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,l,p,f,m,r,q,g;
cin>>n>>l>>p>>f>>m>>r>>q>>g;
int bound=max(p,q)-1,U=2*bound+1,INF=100000000;
vector<int>d(U,INF);
int a=0;
for(int i=1;i<=n;i++){
a=(a+l)%p;
d[(i<=f?-a:a)+bound]=0;
}
for(int i=1;i<U;i++){
d[i]=min(d[i],d[i-1]+1);
}
for(int i=U-2;i>=0;i--){
d[i]=min(d[i],d[i+1]+1);
}
vector<unsigned char>found(U);
int b=0,count=0;
for(int i=1;i<=m;i++){
b=(b+r)%q;
int v=d[(i<=g?-b:b)+bound];
if(!found[v]){
found[v]=1;
count++;
}
}
cout<<count<<'\n';
for(int i=U-1;i>=0;i--){
if(found[i]){
cout<<i<<' ';
}
}
cout<<'\n';
}