zoukankan      html  css  js  c++  java
  • BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)

    题意:N个数,按顺序划分为K组,使得逆序对之和最小。

    思路:之前能用四边形不等式写的,一般网上都还有DP单调性分治的做法,今天也尝试用后者写(抄)了一遍。即:

    分成K组,我们进行K-1次分治,get(l,r,L,R)中如果mid位置的最优解来自MID,那么分别以mid和MID和分界线,有get(l,mid-1,L,MID);get(mid+1,r,MID,R);

     区间逆序对没有什么特别高效的方法,我们用莫对跑ok了。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=40010;
    int a[maxn],sum[maxn],dp[maxn],ans[maxn],N,K,ql,qr,cost;
    inline int query(int x){int res=0;while(x){ res+=sum[x]; x-=(-x)&x;} return res;}
    inline void add(int x,int val){while(x<=N){ sum[x]+=val; x+=(-x)&x;} }
    inline void move(int l,int r)
    {
        while(ql>l) cost+=query(a[--ql]-1),add(a[ql],1);
        while(qr<r) cost+=query(N)-query(a[++qr]),add(a[qr],1);
        while(ql<l) add(a[ql],-1),cost-=query(a[ql++]-1);
        while(qr>r) add(a[qr],-1),cost-=query(N)-query(a[qr--]);
    }
    inline void get(int l,int r,int L,int R)
    {
        if(l>r) return ;
        int mid=(l+r)>>1,Mid;
        for(int i=min(R+1,mid);i>L;i--){
            move(i,mid);
            if(dp[i-1]+cost<ans[mid]) {ans[mid]=dp[i-1]+cost; Mid=i-1;}
        }
        get(l,mid-1,L,Mid); get(mid+1,r,Mid,R);
    }
    int main()
    {
        scanf("%d%d",&N,&K);
        rep(i,1,N) scanf("%d",&a[i]);
        rep(i,1,N) ans[i]=ans[i-1]+query(N)-query(a[i]),add(a[i],1);
        ql=1; qr=N; cost=ans[N];
        rep(i,2,K){
            memcpy(dp,ans,sizeof(ans)); //把上一轮的结果复制
            memset(ans,0x3f,sizeof(ans));
            get(1,N,0,N-1);
        }
        printf("%d
    ",ans[N]);
        return 0;
    }

     我也写了四边形不等式来优化DP,其他部分一样。 然而T了,估计是莫对跑得太多了。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=40010;
    int a[maxn],sum[maxn],dp[maxn][11],pos[maxn][11],N,K,ql,qr,cost;
    inline int query(int x){int res=0;while(x){ res+=sum[x]; x-=(-x)&x;} return res;}
    inline void add(int x,int val){while(x<=N){ sum[x]+=val; x+=(-x)&x;} }
    inline void move(int l,int r)
    {
        while(ql>l) cost+=query(a[--ql]-1),add(a[ql],1);
        while(qr<r) cost+=query(N)-query(a[++qr]),add(a[qr],1);
        while(ql<l) add(a[ql],-1),cost-=query(a[ql++]-1);
        while(qr>r) add(a[qr],-1),cost-=query(N)-query(a[qr--]);
    }
    int main()
    {
        scanf("%d%d",&N,&K);
        rep(i,1,N) scanf("%d",&a[i]);
        memset(dp,0x3f,sizeof(dp)); dp[0][1]=0;
        rep(i,1,N) dp[i][1]=dp[i-1][1]+query(N)-query(a[i]),add(a[i],1);
        ql=1; qr=N; cost=dp[N][1];
        rep(i,2,K){
            rep(j,1,N){
               int L=pos[j][i-1]?pos[j][i-1]:1;
               int R=pos[j+1][i]?pos[j+1][i]:N-1;
               rep(k,L,R) {
                   if(k>=j) continue;
                   move(k+1,j);
                   if(dp[j][i]>dp[k][i-1]+cost){
                       dp[j][i]=dp[k][i-1]+cost;
                       pos[j][i]=k;
                   }
               }
            }
        }
        printf("%d
    ",dp[N][K]);
        return 0;
    }
  • 相关阅读:
    Openjudge-NOI题库-简单算术表达式求值
    洛谷-求同构数的个数-NOIP2013提高组复赛
    洛谷-拼数-NOIP1998提高组复赛
    洛谷-统计数字-NOIP2007提高组复赛
    洛谷-谁拿了最多奖学金-NOIP2005提高组复赛
    Openjudge-NOI题库-字符串移位包含问题
    洛谷-乘积最大-NOIP2000提高组复赛
    NOIP2015-普及组复赛-第一题-金币
    Tyvj-超级书架
    Openjudge-NOI题库-出书最多
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9963452.html
Copyright © 2011-2022 走看看