• 数据结构优化dp


    由于考试考得不太好 一个寒假没碰过笔也没写作业233能考好才怪。

    当然 也不是坏到了极点。当然还可以坚持像以前一样来机房 写一些有意思的题目了!

    早就想A那道题目了,看到qy dalao 去写了我想我也能写。

    对于这道题目 贪心肯定是不行的吧,不知道从哪贪 30分。

    裸的n^2 dp 那么就可以到手了。 f[i]表示 第i个磁带合法的最小代价

    f[i]=min(f[i],f[j]+abs(a[j+1]-(i-j-1)));这样得到了30分 很容易的一个n^2 算法dp

    然后瞄着 70分考虑优化,花费了我3个小时也只想到了 去绝对值。

    设 k=i-i; f[i]=min{f[j]+a[j+1]+j-k}; 当且仅当 a[j+1]+j-k>=0

    或者 f[i]=min(f[j]+k-a[j+1]-j); 当且仅当 a[j+1]+j-k<=0 

    我们发现有两个决策集合 这个斜率优化? 没什么用

    单调队列也不行啊 因为k不具单调性 四边形不等式?(去一边区间dp

    只能是数据结构优化了,树状数组?线段树?亦或者 权值线段树?

    感觉都不太行啊,观察线段树的话我开两个 然后以什么为下标呢 a[j+1]+j 

    好像是可以很大很大的 但是可以离散复杂度稍微高一点且非常不好写。

    qy dalao倒是交给我了一种方法,倒序dp发现很容易解决这个问题,且维护很好维护。

    也很好写,当然我自己也是经过严密的思考(旷了早读,列了一堆式子

    倒序dp:f[i]表示 第后i个磁带合法的最小代价  f[i]=min(f[i],abs(a[i]-j+1+i)+f[j])

    设 k=a[i]+1+i f[i]=min{abs(k-j)+f[j]}那么这个问题如下:

    分类讨论: 当 k-j>=0 时我们需要寻找 k~n 这个决策集合中最小的 f[j]-j ;

                       当k-j<=0 时我们需要寻找 1~k  这个决策集合中最小的 f[j]+j;

    怎么寻找呢 开 multiset? 不太行 因为我们还要维护下标(不用离散 好开心好开心。

    开两个线段树吧,维护一个区间最小值即可。此题结束。

    另外值得一提的是这道题卡常 把我正确率都卡下去了QAQ

    真的是丧心病狂的卡常 我最后把常数都卡到最小了 还是T 1一点。

    无奈我使出了 把两个线段树当成一个线段树用减小近乎一倍的常数A掉了这道题呢!

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<ctime>
    #include<set>
    #include<bitset>
    #include<map>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #define INF 2147483646
    #define INF1 168430090
    #define ll long long
    #define l(x) s[x].l
    #define r(x) s[x].r
    #define v(x) s[x].v
    #define R register
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    void put(int x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    //考虑dp f[i]表示 第i个磁带合法的最小代价 
    //显然 f[i]=min(f[i],abs(a[i]-j+1+i)+f[j])
    //设 k=a[i]+1+i f[i]=min{abs(k-j)+f[j]}
    const int MAXN=1000002;
    int n;
    int f[MAXN],a[MAXN];
    inline int min(int x,int y)
    {
        return x>y?y:x;
    }
    struct wy
    {
        int l,r;
        int v;
    }t[MAXN<<2];//k>=j 的决策区间
    struct wy1//k<=j 的决策区间
    {
        int l,r;
        int v;
    }s[MAXN<<2];
    inline void build(int p,int l,int r)
    {
        t[p].l=l,t[p].r=r;
        l(p)=l;r(p)=r;
        if(l==r)
        {
            if(l==n)t[p].v=-n,v(p)=n;
            else t[p].v=INF,v(p)=INF;
            return;
        }
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        t[p].v=min(t[p<<1].v,t[p<<1|1].v);
        v(p)=min(v(p<<1),v(p<<1|1));
    }
    inline void change(int p,int l,int r,int d,int dd)
    {
        if(l<=t[p].l&&r>=t[p].r){t[p].v=d;v(p)=dd;return;}
        int mid=(t[p].l+t[p].r)>>1;
        if(l<=mid)change(p<<1,l,r,d,dd);
        if(r>mid)change(p<<1|1,l,r,d,dd);
        t[p].v=min(t[p<<1].v,t[p<<1|1].v);
        v(p)=min(v(p<<1),v(p<<1|1));
        return;
    }
    inline int ask(int p,int l,int r)
    {
        if(l<=t[p].l&&r>=t[p].r)return t[p].v;
        int mid=(t[p].l+t[p].r)>>1;
        int cnt=INF;
        if(l<=mid)cnt=min(cnt,ask(p<<1,l,r));
        if(r>mid)cnt=min(cnt,ask(p<<1|1,l,r));
        return cnt;
    }
    inline int ask1(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p))return v(p);
        int mid=(l(p)+r(p))>>1;
        int cnt=INF;
        if(l<=mid)cnt=min(cnt,ask1(p<<1,l,r));
        if(r>mid)cnt=min(cnt,ask1(p<<1|1,l,r));
        return cnt;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        for(R int i=1;i<=n;++i)a[i]=read(),f[i]=INF;;
        n++;build(1,1,n);
        for(R int i=n-1;i>=1;--i)
        {
            R int k=a[i]+i+1;
            f[i]=min(f[i],ask(1,1,k>n?n:k)+k);
            if(k<=n)f[i]=min(f[i],ask1(1,k,n)-k);
            change(1,i,i,f[i]-i,f[i]+i);
        }
        put(f[1]);
        return 0;
    }
    View Code

    时不可兮骤得,聊逍遥兮容与!

  • 相关阅读:
    BZOJ3277: 串(广义后缀自动机)
    BZOJ3998: [TJOI2015]弦论(后缀自动机)
    SPOJ7258 SUBLEX
    洛谷P3808 【模板】AC自动机(简单版)
    SPOJ8222 NSUBSTR
    BZOJ2946 [Poi2000]公共串(后缀自动机)
    Codeforces Round #490 (Div. 3)
    SPOJ1811 LCS
    洛谷P3804 【模板】后缀自动机
    list排序成员函数对string对象与char*对象排序的差别
  • 原文地址:https://www.cnblogs.com/chdy/p/10455210.html
Copyright © 2020-2023  润新知