zoukankan      html  css  js  c++  java
  • BZOJ5125 小Q的书架(决策单调性+动态规划+分治+树状数组)

      设f[i][j]为前i个划成j段的最小代价,枚举上个划分点转移。容易想到这个dp有决策单调性,感性证明一下比较显然。如果用单调栈维护决策就不太能快速的求出逆序对个数了,改为使用分治,移动端点时树状数组维护即可,类似莫队的每次都在原有基础上更新。注意更新时先加再减。感觉复杂度非常玄学丝毫不能看出为啥只需要更新nlog次?

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 40010
    #define M 11
    #define inf 1600000010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    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;
    }
    int n,m,a[N],f[M][N],tree[N],l,r,cur;
    void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;}
    int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
    void update(int L,int R)
    {
        while (r<R) cur+=r-l+1-query(a[r+1]),add(a[++r],1);
        while (l>L) cur+=query(a[l-1]),add(a[--l],1);
        while (r>R) add(a[r--],-1),cur-=r-l+1-query(a[r+1]);
        while (l<L) add(a[l++],-1),cur-=query(a[l-1]);
    }
    void solve(int k,int x,int y,int l,int r)
    {
        if (l>r) return;
        int mid=l+r>>1,id=min(mid-1,y);f[k][mid]=inf;
        for (int i=min(mid-1,y);i>=x;i--)
        {
            update(i+1,mid);
            if (f[k-1][i]+cur<=f[k][mid]) f[k][mid]=f[k-1][i]+cur,id=i;
        }
        solve(k,x,id,l,mid-1);
        solve(k,id,y,mid+1,r);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5125.in","r",stdin);
        freopen("bzoj5125.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();l=1,r=0;
        for (int i=1;i<=n;i++) a[i]=read();
        f[0][0]=0;for (int i=1;i<=n;i++) f[0][i]=inf;
        for (int j=1;j<=m;j++) solve(j,0,n-1,1,n);
        cout<<f[m][n];
        return 0;
    }
  • 相关阅读:
    Sublime Text 2 && MinGW G++ On Windows
    [zz]linux IO(function open read write close)
    PHP的基本常识(1)
    helloworld.c 的一次系统旅行(1) 读书笔记
    PHP 仿博客园 个人博客(1)
    配置 .htaccess 单点入口
    仿博客园个人博客(3)基本完成
    PHP的基本常识(2)
    JQuery 获得所有表单值
    PHP 仿博客园 个人博客(2)
  • 原文地址:https://www.cnblogs.com/Gloid/p/10089594.html
Copyright © 2011-2022 走看看