[BZOJ2090/2089] [Poi2010]Monotonicity 2/Monotonicity 树状数组优化dp

这个dp乍看不科学,仔细一看更不科学,所以作为一个执着BOY,我决定要造数据卡死波兰人民,但是我造着造着就......证出来了.........

这个就是把 < > =分开讨论每次找到f[i] 即以i为结尾的最长长度,然后一顿转移,那么我们发现如果只是讨论 符号那么由于符号顺序影响 我们的得到的是一个有后效性的dp 就是说我们这个时候找到最优解可能会影响最优解的得到,那么这个dp的正确性是怎样的呢?

证明:

首先我们假设我们找到了一个不是全部从最优转移点转移来的最优序列那么:I.最后一个点一定是从最优转移点转移过来 II. 倒数第二个点,如果不是最优转移点的结果,那么他可以把最后一个点顶掉,并且把自己换成最优转移点     (由于我们一直没有改变最优解,所以我们重复I II 就得到了一个最后两位都是最优解的最优序列) III. 然后我们看中间的点,我们总可以得到一个其之后的点都是由最优转移点转移而来的,那么我们可以把他换成最优转移er,那么得到了一个比原来肿了一点的新序列(我们先留着后面的点),那么现在我们的一串点他们之间都有符号,且他们都满足符号,只是现在不满足那个 s数组的顺序,那么我们发现在这次被操作的那个点的左右一段区间的符号是一样的,那么我们只要在这一段区间内删除掉连续的一段大小为新增长度的序列就可以了,我们从中间一个一个的删,删掉就补到中间来这样连续操作就可以了, 如果 中间那个数两边存在 = 就可以随意删,如果两边符号相同即 < < 或  > > 那么中间的店一定可以删掉 如果是 a<b>c 或 a>b<c 那么删掉b再按照a c 大小删掉左右的某个符号就好了,如果是a c相等那么就任意留一个a或c,那么如果我们现在只能删一个怎么办?如果只剩一个的话那么这个东西就是这段区间里唯一的旮沓了,那么他左右两边的符号一定相等(小证明:我们由于采取两边向中间沦陷的策略所以我们剩的点一定是要删除的区间两个边缘点之一,那么我们考虑这个区间,他一定正好覆盖两个轮回中间的一个轮回,那么边缘之一一定和另一个边缘的左出头一样)

我们重复以上操作可以把这个最优解转化为全部由最优转移点转移而来的最优解,因此要是没有一个不是全部从最优转移点转移来的最优序列那么我们的dp一定是对的如果有那么我们一定有全部由最优转移点转移而来的最优解,因此我们的dp一定可以找到最优解

这个故事告诉我们考场证dp是一个正确的选择.......

#include <cstdio>
#include <cstring>
#include <iostream>
#define Inf 1000000
#define MAXN 500000
#define r register
using namespace std;
int L[Inf+10],B[Inf+10];
inline int read()
{
    r int sum=0;
    r char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        sum=(sum<<1)+(sum<<3)+ch-'0';
        ch=getchar();
    }
    return sum;
}
inline void read(int &x)
{
    r char ch=getchar();
    while(ch!='='&&ch!='<'&&ch!='>')ch=getchar();
    x=ch;
}
inline void ins_L(int x,int key){
    while(x<=Inf) L[x]=key>L[x]?key:L[x],x+=x&(-x);
}
inline void ins_B(int x,int key){
    while(x<=Inf) B[x]=key>B[x]?key:B[x],x+=x&(-x);
}
inline int get_B(int x){
    r int ans=0;
    while(x>0) ans=B[x]>ans?B[x]:ans,x-=x&(-x);
    return ans;
}
inline int get_L(int x){
    r int ans=0;
    while(x>0) ans=L[x]>ans?L[x]:ans,x-=x&(-x);
    return ans;
}
int n,k,a[MAXN+10],J[Inf+10];
Init s[MAXN+10];
inline void Init()
{
    n=read(),k=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=k;i++)read(s[i]);
}
inline int Max(int x,int y)
{
    return x>y?x:y;
}
inline void work()
{
    r int Ans=0;
    for(int i=1;i<=n;i++)
    {
       r int ans=0;
       ans=get_B(Inf-a[i]);
       ans=Max(ans,get_L(a[i]-1));
       ans=J[a[i]]>ans?J[a[i]]:ans;
       ans+=1;
       Ans=ans>Ans?ans:Ans;
       r int pos=(ans-1)%k+1;
       if(s[pos]=='<')ins_L(a[i],ans);
       else if(s[pos]=='>')ins_B(Inf+1-a[i],ans);
       else J[a[i]]=J[a[i]]>ans?J[a[i]]:ans;
    }
    printf("%d",Ans);
}
int main()
{
    Init();
    work();
    return 0;
}

 

posted @ 2017-07-27 21:45  TS_Hugh  阅读(320)  评论(0编辑  收藏  举报