\(n^2\) 很好写
发现转移要满足限制条件 \(i<j,\ a[i]-i\geqslant a[j]-j,\ a[i]<a[j]\),于是CDQ,被卡常了第一次写CDQ优化DP是在考场上写的居然还写出来了
然而被出题人耍了……
观察这几个条件,发现若满足 \(a[i]-i\geqslant a[j]-j,\ a[i]<a[j]\) 则一定有 \(i<j\) 成立
所以按 \(a[i]\) 排个序后就是找前面 \(a[i]-i\) 大的转移了
然后每个决策点的贡献只有1
所以其实直接求个最长不下降子序列就行了
- 所以以后推出来限制条件或者不等式啥的先看看能不能合并啥的
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500050
#define ll long long
//#define int long long
#define max(a, b) ((a)>(b)?(a):(b))
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
int a[N];
namespace force{
int dp[1010][1010], ans;
void solve() {
for (int i=1; i<=n; ++i) {
for (int j=1; j<=i; ++j) {
dp[i][j]=max(dp[i-1][j], dp[i-1][j-1]+(a[i]==j?1:0));
ans=max(ans, dp[i][j]);
}
}
printf("%d\n", ans);
exit(0);
}
}
namespace task1{
int dp[N], ans;
void solve() {
memset(dp, -1, sizeof(dp));
dp[0]=0;
for (int i=1; i<=n; ++i) {
for (int j=0; j<i; ++j) if (a[i]>a[j] && a[i]-i<=a[j]-j)
dp[i]=max(dp[i], dp[j]);
if (~dp[i]) ++dp[i];
ans=max(ans, dp[i]);
}
printf("%d\n", ans);
exit(0);
}
}
namespace task2{
int dp[N], ans, uni[N], usize, bin[N], lim, tot;
struct grp{int a, b, c; inline void build(int x, int y, int z) {a=x; b=y; c=z;}}p[N];
inline bool cmp1(grp a, grp b) {return a.a==b.a?(a.b==b.b?a.c<b.c:a.b>b.b):a.a<b.a;}
inline bool cmp2(grp a, grp b) {return a.b==b.b?a.c<b.c:a.b>b.b;}
inline void upd(int i, int dat) {++i; for (; i<=lim; i+=i&-i) bin[i]=max(bin[i], dat);}
inline int query(int i) {++i; int ans=-1; for (; i; i-=i&-i) ans=max(ans, bin[i]); return ans;}
inline void del(int i) {++i; for (; i<=lim; i+=i&-i) bin[i]=-1;}
void cdq(int l, int r) {
if (l==r) {
if (p[l].a!=0 && ~dp[p[l].a]) ++dp[p[l].a];
return ;
}
int mid=(l+r)>>1;
cdq(l, mid);
sort(p+l, p+mid+1, cmp2); sort(p+mid+1, p+r+1, cmp2);
// cout<<"lr: "<<l<<' '<<r<<endl;
// cout<<"p: "; for (int i=l; i<=r; ++i) cout<<p[i].a<<' '; cout<<endl;
int pos1=l, pos2=mid+1;
for (; pos2<=r; ++pos2) {
while (pos1<=mid && p[pos1].b>=p[pos2].b) upd(p[pos1].c, dp[p[pos1].a]), ++pos1;
// if (l==3 && r==4) cout<<"pos: "<<pos1<<' '<<pos2<<endl;
// cout<<"c: "<<p[pos1-1].c<<' '<<p[pos2].c<<endl;
int tem=query(p[pos2].c-1);
if (~tem) dp[p[pos2].a]=max(dp[p[pos2].a], tem);
}
for (int i=l; i<pos1; ++i) del(p[i].c);
sort(p+l, p+r+1, cmp1);
cdq(mid+1, r);
}
void solve() {
memset(dp, -1, sizeof(dp));
memset(bin, -1, sizeof(bin));
dp[0]=0;
// for (int i=1; i<=n; ++i) uni[i]=a[i];
// uni[n+1]=0;
// sort(uni+1, uni+n+2);
// usize=unique(uni+1, uni+n+2)-uni-1; lim=usize+3;
lim=n+3;
for (int i=1; i<=n; ++i) if (a[i]<=i) p[++tot].build(i, a[i]-i, a[i]+1);
sort(p, p+n+1, cmp1);
cdq(0, n);
// cout<<"dp: "; for (int i=1; i<=n; ++i) cout<<dp[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) ans=max(ans, dp[i]);
printf("%d\n", ans);
exit(0);
}
}
signed main()
{
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) a[i]=read();
// force::solve();
// task1::solve();
task2::solve();
return 0;
}