2 条题解
-
0
题目大意
给定长度为 的序列 。可以删除任意个元素,其余元素保持原顺序并“下落”重新编号。
要求最大化重排后满足 的位置个数。即选出尽可能多的元素,得它们在新序列中位于“正确”的位置。
思路
假设我们保留了原序列中 个位置 。删除其余元素后,新序列第 个元素为原序列的 。 需要满足 ,同时由于 是第 个被保留的元素,必须有 。
对于 ,有 (因为值必须分别为 和 ),且 。
由 可推出 。
有了这些性质就好办了,定义 表示以原序列第 个元素结尾并且能得到的最大满足条件的个数。
转移就很好转移了。
#include<bits/stdc++.h> using namespace std; int n,a[100005],ans,f[100005]; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++){ if(a[i]>i) continue; for(int j=0;j<i;j++){ if(a[i]<=a[j]) continue; if(a[i]-a[j]<=i-j) f[i]=max(f[i],f[j]+1); } ans=max(ans,f[i]); } cout<<ans; }时间复杂度是 ,那怎么优化呢?可以用树状数组来优化,但树状数组只可以维护 的最大值,所以维护的区间要转换成 。
可以转换成 可以转换成 ,于是就变成求 的最大值。
#include<bits/stdc++.h> using namespace std; int n,a[200005],ans,f[200005],t[200005]; pair<int,int> b[200005]; void add(int i,int d){ while(i<=200000){ t[i]=max(t[i],d); i+=(i&(-i)); } } int sum(int i){ int res=0; while(i){ res=max(res,t[i]); i-=(i&(-i)); } return res; } int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i],b[i]={a[i],i}; sort(b+1,b+1+n); for(int i=1,j;i<=n;i++,i=j){ j=i; while(b[i].first==b[j].first) j++; for(int k=i;k<j;k++){ if(b[k].first>b[k].second) continue; f[b[k].second]=max(f[b[k].second],sum(n-b[k].first+b[k].second)+1); ans=max(ans,f[b[k].second]); } for(int k=i;k<j;k++){ if(b[k].first>b[k].second) continue; add(n-b[k].first+b[k].second,f[b[k].second]); } } cout<<ans; } -
0
60分代码:
#include <bits/stdc++.h> using namespace std; constexpr int N = 1e5 + 5; int a[N], f[N]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); memset(f, 0, sizeof(f)); for (int i = 1; i <= n; i++) { f[0] = f[0] + (a[i] == 0 ? 1 : 0); for (int j = i; j >= 1; j--) f[j] = max(f[j] + (a[i] == i - j ? 1 : 0), f[j - 1]); } int ans = 0; for (int i = 1; i <= n; i++) ans = max(ans, f[i]); printf("%d\n", ans); return 0; }
- 1
信息
- ID
- 2762
- 时间
- 500ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 22
- 已通过
- 7
- 上传者