У меня есть прогрессия "a", где даны первые два числа (a1 и a2), а каждое следующее число - наименьшая сумма подмассива, которая больше, чем предыдущее число.
Например, если у меня есть a1 = 2 и a2 = 3, то прогрессия будет
2, 3, 5 (= 2 + 3), 8 (= 3 + 5), 10 (= 2 + 3 + 5), 13 (= 5 + 8), 16 (= 3 + 5 + 8) ,
18 (= 2 + 3 + 5 + 8 = 8 + 10), 23 (= 5 + 8 + 10 = 10 + 13), 26 (= 3 + 5 + 8 + 10), 28 (= 2 + 3 + 5) + 8 + 10), 29 (= 13 + 16) ...
Мне нужно найти N-е число в этой прогрессии. (Ограничение по времени составляет 0,7 секунды)
(a1 меньше a2, a2 меньше 1000 и N меньше 100000)
Я пробовал приоритетную очередь, сет, карту, https://www.geeksforgeeks.org/find-subarray-with-given-sum/ и некоторые другие вещи.
Я думаю, что очередь с приоритетом будет работать, но она превышает лимит памяти (256 МБ), поэтому я почти безнадежен.
Вот то, что работает лучше всего на данный момент.
int main(){
int a1, a2, n;
cin>>a1>>a2>>n;
priority_queue< int,vector<int>,greater<int> > pq;
pq.push(a1+a2);
int a[n+1];//contains sum of the progression
a[0]=0;
a[1]=a1;
a[2]=a1+a2;
for(int i=3;i<=n;i++){
while(pq.top()<=a[i-1]-a[i-2])
pq.pop();
a[i]=pq.top()+a[i-1];
pq.pop();
for(int j=1; j<i && a[i]-a[j-1]>a[i]-a[i-1] ;j++)
pq.push(a[i]-a[j-1]);
}
cout<<a[n]-a[n-1];
}
Я пытался решить эту проблему последние 4 дня безуспешно.
Извините за плохой английский, мне всего 14, а не англоязычный.
РЕШЕНИЕ (Большое спасибо n.m. и גלעד ברקן)
V1 (н.м. раствор)
using namespace std;
struct sliding_window{
int start_pos;
int end_pos;
int sum;
sliding_window(int new_start_pos,int new_end_pos,int new_sum){
start_pos=new_start_pos;
end_pos=new_end_pos;
sum=new_sum;
}
};
class Compare{
public:
bool operator() (sliding_window &lhs, sliding_window &rhs){
return (lhs.sum>rhs.sum);
}
};
int main(){
int a1, a2, n;
//input
cin>>a1>>a2>>n;
int a[n+1];
a[0]=a1;
a[1]=a2;
queue<sliding_window> leftOut;
priority_queue< sliding_window, vector<sliding_window>, Compare> pq;
//add the first two sliding window positions that will expand with time
pq.push(sliding_window(0,0,a1));
pq.push(sliding_window(1,1,a2));
for(int i=2;i<n;i++){
int target=a[i-1]+1;
//expand the sliding window with the smalest sum
while(pq.top().sum<target){
sliding_window temp = pq.top();
pq.pop();
//if the window can't be expanded, it is added to leftOut queue
if(temp.end_pos+1<i){
temp.end_pos++;
temp.sum+=a[temp.end_pos];
pq.push(temp);
}else{
leftOut.push(temp);
}
}
a[i]=pq.top().sum;
//add the removed sliding windows and new sliding window in to the queue
pq.push(sliding_window(i,i,a[i]));
while(leftOut.empty()==false){
pq.push(leftOut.front());
leftOut.pop();
}
}
//print out the result
cout<<a[n-1];
}
V2 (решение גלעד ברקן)
int find_index(int target, int ps[], int ptrs[], int n){
int cur=ps[ptrs[n]]-ps[0];
while(cur<target){
ptrs[n]++;
cur=ps[ptrs[n]]-ps[0];
}
return ptrs[n];
}
int find_window(int d, int min, int ps[], int ptrs[]){
int cur=ps[ptrs[d]+d-1]-ps[ptrs[d]-1];
while(cur<=min){
ptrs[d]++;
cur=ps[ptrs[d]+d-1]-ps[ptrs[d]-1];
}
return ptrs[d];
}
int main(void){
int a1, a2, n, i;
int args = scanf("%d %d %d",&a1, &a2, &n);
if (args != 3)
printf("Failed to read input.\n");
int a[n];
a[0]=a1;
a[1]=a2;
int ps[n+1];
ps[0]=0;
ps[1]=a[0];
ps[2]=a[0]+a[1];
for (i=3; i<n+1; i++)
ps[i] = 1000000;
int ptrs[n+1];
for(i=0;i<n+1;i++)
ptrs[i]=1;
for(i=2;i<n;i++){
int target=a[i-1]+1;
int max_len=find_index(target,ps, ptrs, n);
int cur=ps[max_len]-ps[0];
int best=cur;
for(int d=max_len-1;d>1;d--){
int l=find_window(d, a[i-1], ps, ptrs);
int cur=ps[l+d-1]-ps[l-1];
if(cur==target){
best=cur;
break;
}
if(cur>a[i-1]&&cur<best)
best=cur;
}
a[i]=best;
ps[i+1]=a[i]+ps[i];
}
printf("%d",a[n-1]);
}