首页 > 其他 > 详细

牛客OI周赛3-提高组-B-1408[dp]

时间:2018-10-22 17:36:31      阅读:168      评论:0      收藏:0      [点我收藏+]

题意

给你长度为 \(n\) 的两个排列 \(A,B\) 组成的序列,求最少的交换相邻数字的次数使得 \(A,B\) 分别有序。

\(n\leq 2000\) .

分析

  • 如果只有一个排列时最少交换次数为逆序对数,方案可从小到大枚举数字 \(a_i\),并向左移动直到前面的数有序且没有比 \(a_i\)大的数为止。

  • 发现当前序列的每个数字仍然会按照上述方式交换,否则逆序对仍要交换且还有多余的部分。

  • 只是两个序列的错杂交换会相互影响,于是考虑定义状态 \(f_{i,j}\) 表示 \(A\) 序列的前 \(i\) 个有序,\(B\) 序列的前 \(j\) 个有序(一定占据了前 \((i+j)\) 个位置)最小的交换次数。每次枚举是哪一边交换并查询还需要和前面的多少个元素交换即可。

  • 总时间复杂度为 \(O(n^2logn)\)

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=4004 + 7,inf=0x3f3f3f3f;
int n;
int a[2][N],tr[N],f[N][N];
char s[10];
int lowbit(int x){return x&-x;}
void modify(int x,int y){for(int i=x;i<=2*n;i+=lowbit(i)) tr[i]+=y;}
int query(int x){int res=0;for(int i=x;i;i-=lowbit(i)) res+=tr[i];return res;}
int main(){
    n=gi();
    rep(i,1,2*n){
        int x;
        scanf("%s%d",s,&x);
        a[s[0]=='W'][x]=i;
        modify(i,1);
    }
    a[0][0]=a[1][0]=2*n+1;
    memset(f,0x3f,sizeof f);
    f[0][0]=0;
    rep(i,0,n){
        modify(a[0][i],-1);
        rep(j,0,n){
            modify(a[1][j],-1);
            if(i||j){
                if(i) Min(f[i][j],f[i-1][j]+query(a[0][i]-1));
                if(j) Min(f[i][j],f[i][j-1]+query(a[1][j]-1));
            }
        }
        rep(j,0,n) modify(a[1][j],1);
    }
    printf("%d\n",f[n][n]);
    return 0;
}

牛客OI周赛3-提高组-B-1408[dp]

原文:https://www.cnblogs.com/yqgAKIOI/p/9831003.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!