Counting Arithmetic Subsequences
National Olympiad — Regional round (2017 season)
Submission name: progres.cpp
Problem summary
Count position-distinct subsequences of length at least two forming a strictly increasing arithmetic progression, modulo 123456789012345.
Input
N and N positive integers.
Output
Number of arithmetic subsequences modulo the given modulus.
Constraints
1 < N < 1000; 1 ≤ value ≤ 1000.
Worked example
An independently prepared example for this explanation.
Input
3 1 2 3
Output
4
Solution analysis
- Let dp[i][d] count arithmetic subsequences of length at least two that end at position i with positive common difference d. Differences can only be 1…999.
- For each earlier j with a[j]<a[i], set d=a[i]−a[j]. Append a[i] to every subsequence counted by dp[j][d], and also count the new two-element subsequence (j,i). Add dp[j][d]+1 to dp[i][d] and to the answer.
- For 1,2,3, the pairs (1,2),(2,3),(1,3) contribute three sequences, and extending (1,2) produces (1,2,3), giving four. Equal-valued positions are separate choices but never form a positive-difference pair.
Why it works
Every counted progression has a unique penultimate position j and positive difference d. Removing its last element leaves either a one-element prefix, counted by the added one, or a progression counted by dp[j][d]. These cases are disjoint, so the recurrence counts each legal position sequence once.
Watch out. Subsequences need not be contiguous. Equal value sequences at different positions count separately. Exclude d=0 and reduce every addition modulo the specified 15-digit modulus.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<vector>
// Algorithm: Let dp[i][d] count arithmetic subsequences of length at least two that end at
// position i with positive common difference d.
using namespace std;
int main(){
int n;
cin>>n;
vector<int>a(n);
for(int&value:a){
cin>>value;
}
const long long mod=123456789012345LL;
vector<vector<long long>>dp(n,vector<long long>(1000,0));
long long answer=0;
for(int i=0;i<n;++i){
for(int j=0;j<i;++j){
int difference=a[i]-a[j];
if(difference<=0){
continue;
}
long long added=(dp[j][difference]+1)%mod;
dp[i][difference]=(dp[i][difference]+added)%mod;
answer=(answer+added)%mod;
}
}
cout<<answer<<'\n';
}