Solution of 1029B. Creating the Contest
Difference between en3 and en4, changed 2 character(s)
This is the second problem of Div.3. But I think it is not easy.↵

Problem:[problem:1029B]↵

Simple Meaning of Problem:↵

There is a sequence $a$ and you should choose the longest sequence $b$ ${a_{i_1}, a_
{i_2}, \dots, a_{i_p}}$ ($p$ is the length of $b$) such that:each $j∈[1,k)$ $a_{i_{j+1}} \le a_{i_j} \cdot 2$ should hold.↵

print the maximum number of $p$ (the length of $b$)↵


First, you can enumerate which ones to choose. You will get a algorithm with $O(2^n)$. And you will get a Time Limit Exceed.(I didn't write it, because it is valueless.)↵

Then, dp is another useful algorithm. So we can try to use dp.↵

$f[i]$ means that if you choose the number $a_i$, you can get the maximum $p$ (only of $1$ to $i$).↵

It is very easy to get the state transition equation:↵

$f[i]=max{f[j]}+1$, $j$ satisfy that $a_i \le a_j \cdot 2$ and $j \le i$.↵

And the answer is $max{f[i]}$ ($i$ is $1$ to $n$).↵

code:[submission:42093398]↵

~~~~~↵
#pragma comment (linker,"/STACK:1024000000") ↵
#pragma GCC optimize(2)↵
#pragma GCC target(arch=corie7-acx)↵
#include<bits/stdc++.h>↵
using namespace std;↵
int n,a[200001],f[200001];↵
deque <int> q;↵
int t,ans;↵
int main()↵
{↵
scanf("%d",&n);↵
for (int i=1;i<=n;i++)↵
scanf("%d",&a[i]);↵
f[1]=1;↵
for (int i=2;i<=n;i++)↵
{↵
for (int j=1;j<=i-1;j++)↵
if (a[j]*2>=a[i]) f[i]=max(f[i],f[j]);↵
f[i]++;↵
}↵
for (int i=1;i<=n;i++)↵
ans=max(ans,f[i]);↵
printf("%d",ans);↵
return 0;↵
}↵
~~~~~↵

And this code does better:[submission:42095786](In fact, it also Time Limit Exceed on Test 4)↵

~~~~~↵
#pragma comment (linker,"/STACK:1024000000") ↵
#pragma GCC optimize(2)↵
#pragma GCC target(arch=corie7-acx)↵
#include<bits/stdc++.h>↵
using namespace std;↵
int n,a[200001],f[200001];↵
deque <int> q;↵
int t,ans;↵
int main()↵
{↵
scanf("%d",&n);↵
for (int i=1;i<=n;i++)↵
scanf("%d",&a[i]);↵
f[1]=1;↵
for (int i=2;i<=n;i++)↵
{↵
for (int j=i-1;j>=1;j--)↵
if (a[j]*2>=a[i]) f[i]=max(f[i],f[j]);↵
else break;↵
f[i]++;↵
}↵
for (int i=1;i<=n;i++)↵
ans=max(ans,f[i]);↵
printf("%d",ans);↵
return 0;↵
}↵
~~~~~↵

But, unfortunately, these two are both Time Limit Exceed. (Actually, it is inevitable.)↵
 ↵
Because when $a_n \le a_1 \cdot 2$, the time complexity of the code will come to $O(n^2)$ (`break` is useless).↵

So it is inevitable that the code will TLE.↵

Now, how can we optimize our algorithm?↵

In the problem, notice that the numbers are increasing.↵

So when $i$ is increasing, $a_i$ is increasing, too. And $\frac {a_i} {2}$ is increasing, so the number which is less than $\frac {a_i} {2}$ is also increasing.↵

Because of this, for the increasing number $i$, the $j$ which is satisfy $a_i \le a_j \cdot 2$ is increasing as well.↵

So we can maintain a queue. The number of the queue means the number of $a$'s number.↵

When we want to calculate $f[i]$, we check the numbers of queue from the front to the back. For each $x$, if $a_x \cdot 2 < a_i$, we can pop $x$. (Because for the after $j$, $a_j \ge a_i > a_x \cdot 2$).↵

We can find the first $x$ which is satisfy $a_x \cdot 2 \ge a_i$. Then we use $f[x]$ to calculate $f[i]$. (It will be proven after).↵

Finally, we get the back of $q$ $y$. If $f[y] \le f[i]$, we can pop $y$. That's because $y$ must be popped earlier than $i$, and $f[i]$ is greater than $f[y]$. So the following number choose $f[i]$ is greater than $f[y]$.↵

And that's why the first number of the queue $x$ is the best choice to transfer $f[i]$ after popping. (In fact, it is a priority queue.)↵

When we code it, we can use double-end-queue (deque).↵

code:[submission:42036114]↵

~~~~~↵
#pragma comment (linker,"/STACK:1024000000") ↵
#pragma GCC optimize(2)↵
#pragma GCC target(arch=corie7-acx)↵
#include<bits/stdc++.h>↵
using namespace std;↵
int n,a[200001],f[200001];↵
deque <int> q;↵
int t,ans;↵
int main()↵
{↵
scanf("%d",&n);↵
for (int i=1;i<=n;i++)↵
scanf("%d",&a[i]);↵
f[1]=1;↵
q.push_back(1);↵
for (int i=2;i<=n;i++)↵
{↵
while (!q.empty())↵
{↵
t=q.front();↵
if (a[t]*2<a[i]) q.pop_front();↵
else break;↵
}↵
if (q.empty()) t=0;↵
f[i]=f[t]+1;↵
while (!q.empty())↵
{↵
t=q.back();↵
if (f[t]<f[i]) q.pop_back();↵
else break;↵
}↵
q.push_back(i);↵
}↵
for (int i=1;i<=n;i++)↵
ans=max(ans,f[i]);↵
printf("%d",ans);↵
return 0;↵
}↵
~~~~~↵

Thank you for reading my first entry. See you next time!↵

postscripts:↵

1. It is the first time of mine to write the solution (entry). So if there is any mistake, please specify ([user:PQF,2018-08-27]). Thanks.↵
1. Actually, I'm a Chinese. So please forgive my English level. Thanks.↵
1. Oh, writing an entry is so tiring!

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en6 English Theory_of_Everything 2018-08-27 10:21:19 38
en5 English Theory_of_Everything 2018-08-27 10:18:56 237
en4 English Theory_of_Everything 2018-08-27 09:51:44 2
en3 English Theory_of_Everything 2018-08-27 09:41:22 1915 (published)
en2 English Theory_of_Everything 2018-08-27 09:12:22 440 Tiny change: '$O(n^2)$ (breakbreakbreak is useles' -> '$O(n^2)$ (`break` is useles'
en1 English Theory_of_Everything 2018-08-25 19:20:05 2329 Initial revision (saved to drafts)