著名的植物学家 Alice 经过多年的探索,终于找到了传说中的璀璨花。璀璨花的生长速度非常迅猛,如果不加以合适的控制,璀璨花会因为过度内耗而死亡。璀璨花的生长趋势可以用序列 \(a\) 表示,Alice 在研读前人对璀璨花的研究后总结出了一个控制序列 \(b\)。Alice 需要让璀璨花的生长趋势尽可能贴合控制序列,这样璀璨花就能尽可能快且安全地生长,以让更多人能欣赏到传说花卉的美。
Alice 可以通过基因编辑技术让 \(a\) 的任意子序列 \(a'\) 成为璀璨花的生长趋势,设 \(a'\) 的长度为 \(n'\),若 \(\forall i \in [1,n' - 1],a'_{i + 1} > b_i a'_i\),那么璀璨花的培育趋势就是安全的。另外,越长的生长趋势能让成熟的璀璨花更美,所以 Alice 想知道可能的最长的璀璨花生长趋势子序列的长度。
设 \(dp_{i,j}\) 表示前 \(i\) 个数中选 \(j\) 个数的最小结尾,可以得出转移方程:
-
若 \(a_i > dp_{i - 1,j - 1} b_{j - 1}\),那么 \(dp_{i,j} = \min(a_i,dp_{i - 1,j})\)。
-
若 \(a_i \leq dp_{i - 1,j - 1} b_{j - 1}\),那么 \(dp_{i,j} = dp_{i - 1,j}\)。
显然可以用滚动数组压掉一维。
但转移还是 \(O(n ^ 2)\) 的,考虑到 \(dp_{i - 1}\) 是单调不减的,我们 lower_bound 一个位置 \(p\),满足 \(dp_{i - 1,p - 1} < a_i\),\(dp_{i - 1,p} \geq a_i\)
,发现 \(\forall j \in[1,p],dp_{i,j} = dp_{i - 1,j}\)(因为 \(dp_{i - 1,j} < a_i\)),\(\forall j \in[p + 1,n],dp_{i,j} = dp_{i - 1,j}\)(因为 \(dp_{i,j - 1}\) 已经大于 \(a_i\) 了,那么 \(dp_{i,j - 1} b_{j - 1}\) 肯定大于 \(a_i\))。
最后总复杂度 \(O(n \log n)\)。
//不开 long long 见祖宗
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 9,INF = 0x7f7f7f7f7f7f7f7f;
int n;
int a[N],b[N];
int dp[N];
signed main(){
//freopen("alice.in","r",stdin);
//freopen("alice.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i = 1;i <= n;i++)
cin >> a[i];
for(int i = 1;i <= n;i++)
cin >> b[i];
memset(dp,0x7f,sizeof dp);
dp[0] = 0;
for(int i = 1;i <= n;i++){
int pos = lower_bound(dp + 1,dp + n + 1,a[i]) - dp;
if(a[i] > dp[pos - 1] * b[pos - 1])
dp[pos] = min(dp[pos],a[i]);
}
for(int ans = n;ans >= 1;ans--)
if(dp[ans] != INF){
cout << ans;
break;
}
return 0;
}
标签:24,10,int,璀璨,Alice,long,pos,dp
From: https://www.cnblogs.com/5002-qwq/p/18499393