1. 程式人生 > >#46 delete(動態規劃+樹狀數組)

#46 delete(動態規劃+樹狀數組)

+= namespace 我們 觀察 getc 位置 沒有 spa ins

  二維的dp非常顯然,但這也沒有什麽優化的余地了。

  註意到最後的方案中只有產生貢獻的位置是有用的,剩下的部分可以在該範圍內任意選取。

  所以我們考慮設f[i]為i號位最後產生貢獻的答案,則f[i]=max{f[j]+1} (i-j>=a[i]-a[j],a[i]>a[j])。

  觀察這個限制,即為i-a[i]>=j-a[j]且a[i]>a[j],以及i>j。可以發現這裏i>j的限制是可以被前兩個限制所包含的。於是我們考慮換個順序dp,按照a[i]從小到大來。樹狀數組維護即可。

  至於刪數數量,只需要保證i-a[i]<=k<=n-a[i]。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=
9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1000010 int n,m,tree[N]; struct data { int i,x,ans; bool operator <(const data&a) const { return x<a.x; } }a[N]; void ins(int k,int x){while (k<=n) tree[k]=max(tree[k],x),k+=k&-k;} int
query(int k){int s=0;while (k) s=max(tree[k],s),k-=k&-k;return s;} int main() { #ifndef ONLINE_JUDGE freopen("b.in","r",stdin); freopen("b.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].i=i,a[i].ans=-N; sort(a+1,a+n+1); memset(tree,200,sizeof(tree)); ins(1,0); for (int i=1;i<=n&&a[i].x<=n;) { int t=i-1; while (t<n&&a[t+1].x==a[i].x) { t++; if (a[t].i>=a[t].x) a[t].ans=query(a[t].i-a[t].x+1)+1; } while (i<=t) { if (a[i].i>=a[i].x) ins(a[i].i-a[i].x+1,a[i].ans); i++; } } for (int i=1;i<=n;i++) if (a[i].i-a[i].x<=m&&m<=n-a[i].x) a[0].ans=max(a[0].ans,a[i].ans); cout<<a[0].ans; return 0; }

#46 delete(動態規劃+樹狀數組)