CF 584E(Anton and Ira-构造+贪心)

已知2个排列a,b,交换第i位位与第j位代价=abs(i-j) ,求把排列a变成排列b最小代价及任一合法方案

先把第一个排列变成顺序的

我们考虑对 i 最终要移到bi ,代价=|ibi|
最小总代价ans=12ni=1|ibi|

不妨假设这是答案,
那么每个数只能往一个方向挪,
我们从n开始,不断找可以交换的数交换,显然可以挪到n。
递归做完即可

#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a));
#define pb push_back
#define mp make_pair 
#define MAXN (2000+10)
#define fi first
#define se second
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int n;
int a[MAXN],b[MAXN],h[MAXN];
vector<pair<int,int> > p;
int main()
{
//  freopen("CF584E.in","r",stdin);

    cin>>n;
    For(i,n) scanf("%d",&b[i]);
    For(i,n) scanf("%d",&a[i]);
    For(i,n) h[a[i]]=i;
    For(i,n) b[i]=h[b[i]]; 
    For(i,n) h[b[i]]=i;

    int ans=0,k=0;

    ForD(i,n) {
        int pos=h[i];
        Fork(j,pos+1,i)
        {
            if (b[j]<=pos)
            {
                p.pb(mp(j,pos));
                ans+=abs(j-pos);
                swap(b[j],b[pos]); swap(h[b[j]],h[b[pos]]);
                pos=j;
            }

        }   

    }
    int m=p.size();
    cout<<ans<<endl<<m<<endl;
    Rep(i,m) printf("%d %d\n",p[i].fi,p[i].se);


    return 0;
}
请使用c++14 ## 题目描述 南极的科学家发现了一种新生物!他们获取了一个样本到实验室进行繁殖。 他们很快注意到这种生物经常繁殖而且是单亲繁殖的。但每个个体最多繁殖两次,之后就会失去繁殖能力。 实验室中这种生物的个体数量迅速增加,需要绘制一份家谱。 他们打算把家谱画成如下的一棵树: 家谱以字符图形式表示,名字写在用符号 `-`、`|` 和 `o` 组成一个框内。框的上下边的中点用 `+` 标出。如果框的长度是偶数,那么 `+` 会标在两个中间位置的靠左一个。 ``` o--+--o o----+----o o-+--o |anton| |anamarija| |pero| o--+--o o----+----o o-+--o ``` 这些框会用一些边连起来。一组边可以将两个或多个盒子的 `+` 符号给连起来,父代的框在子代的上方。框和边都不能互相重叠。 ``` + + + | | | o o---o---o o-----o-----o | | | | | + + + + + ``` 如果一个父代生物只有一个子代,那么我们用最左侧的点到点的边把他们连起来。如果有两个子代,那么我们用有分支的边,**年长的子代生物在左侧,年幼的在右侧**。 分支的边可以在水平方向上无限伸长,但是要保证左右两侧的 `-` 字符是一样多的,但是**不能竖直伸长**。 别着急,你不用把这棵树真的画出来。你只需要求出来最少需要多少个字符就可以画出这样的树。**不计空格**,只计算 `-`、`|`、`+`、`o` 和它们的名字所需要的字符。 ## 输入格式 第一行一个整数 $N$ $(1 \le N \le 300\ 000)$,表示实验室中的生物总数。 生物按照出生的顺序从 $1$ 到 $N$ 编号,最年长的是 $1$,最年幼的是 $N$。 接下来的 $N$ 行按照编号顺序给出了一个生物的信息。每一个生物都有如下两个信息: - 名字:一个由不超过 $20$ 个小写英文字母组成的字符串。 - 亲代:一个整数,表示该生物的亲代的编号(第一个生物没有输入这个信息)。 ## 输出格式 一行一个整数,表示最少需要多少个字符可以画下家谱。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 adam kain 1 abel 1 ``` ### 输出 #1 ``` 64 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 12 anton ana 1 luka 1 mia 2 tea 3 jakov 3 semiramida 5 dominik 5 anamarija 4 eustahije 4 lovro 2 lovro 11 ``` ### 输出 #2 ``` 371 ``` ## 说明/提示 ``` o-+--o |adam| o-+--o | o--o--o | | o-+--oo-+--o |kain||abel| o-+--oo-+--o ``` ``` o--+--o |anton| o--+--o | o------------o------------o | | o-+-o o-+--o |ana| |luka| o-+-o o-+--o | | o-------o-------o o--o--o | | | | o-+-o o--+--o o-+-oo--+--o |mia| |lovro| |tea||jakov| o-+-o o--+--o o-+-oo--+--o | | | o-----o-----o o o-----o-----o | | | | | o----+----o o----+----o o--+--oo----+-----o o---+---o |anamarija| |eustahije| |lovro||semiramida| |dominik| o----+----o o----+----o o--+--oo----+-----o o---+---o ``` 可以数出字符数分别是 $64$ 和 $371$ 个。 对于 $50\%$ 的数据,有 $N < 300$。 对于 $75\%$ 的数据,有 $N < 3000$。
最新发布
11-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值