8.15 完美交换 2699

题目

你和你的伙伴们将礼物都装好了,你们抱着各自的礼物,想通过交换让你们总和的完美值最大。你们的 总和完美值 的计算方法是:每个人的位置*每人礼物的完美值 再求总和。

我们保证每个人手上的完美值都不等。
如下表:
位置 1 2 3 4
所拿礼物的完美值 200 400 100 430
当前的 总和完美值=1200+2400+3100+4430
现在你们通过两两交换,要使得最终你们的完美值为最大。
如上例子:经过交换后
位置 1 2 3 4
所拿礼物的完美值 100 200 400 430
总和完美值的最大值=1100+2200+3400+4430
现在要求出最大完美值是多少。另外假设在一个时间单位内,一个人只可以做一次的交换动作(当然也可以原地不动),那么达到最大完美值状态的最短用时是多少。

对于30%的数据N≤10
对于全部的数据N≤104
对于全部的数据Mi≤100050

题解

对于第一个要求——最大完美值,由乱序和小于有序和可得,快排后a[i]*i即答案。
注意Pascal多关键字快排有一种很神奇的错误,关键字应预先处理好,例key和key2,不能是a[key]和b[key],不然会出错(我也不知道为什么)

至于第二个要求——达到最大完美值的最小操作时间
注意可以有多个不同的人在同一时间进行交换!
通过观察可以发现(虽然我没有发现),需要进行交换的序列总是会形成若干环,如2 3 4 5 1为2->3->4->5->1(->2)。如我们用贪心策略使得每次操作有尽可能多的值归位,通过举例可发现贪心策略行不通。包含值的个数为2的环交换次数为1,那么我们可以尽可能的把一个环划分成多个个数为2的环。可以证明一个环至多通过1个时间单位的交换即可转换成多个个数为2的环。于是问题变得简单了:交换次数取决于序列中最大的环的个数,答案存在0,1,2三种可能。

时间复杂度O(n)

代码

var
  n,i,j,k,m:longint;
  a,b,c,f:array[0..100500]of longint;
  max:int64;

procedure qsort(l,r:longint);
var
  i,j,key,t,c:longint;
begin
  if l>=r then exit;
  i:=l;j:=r;
  key:=a[(l+r) div 2];
  c:=b[(l+r) div 2];
  repeat
    while (a[i]<key)or((a[i]=key)and(b[i]<c)) do inc(i);
    while (a[j]>key)or((a[j]=key)and(b[j]>c)) do dec(j);
    if i<=j then
      begin
        t:=a[i];a[i]:=a[j];a[j]:=t;
        t:=b[i];b[i]:=b[j];b[j]:=t;
        inc(i);dec(j);
      end;
  until i>j;
  qsort(i,r);
  qsort(l,j);
end;

begin
//  assign(input,'change.in');
//  assign(output,'change.out');
//  reset(input);rewrite(output);
  readln(n);
  for i:=1 to n do
    begin
      readln(a[i]);
      b[i]:=i;
    end;
  qsort(1,n);
  for i:=1 to n do
    max:=max+a[i]*i;
  writeln(max);
  for j:=1 to n do
    if (f[j]=0)and(b[j]<>j) then
      begin
        k:=0;
        i:=b[j];
        fillchar(c,sizeof(c),0);
        while c[i]=0 do
          begin
            c[i]:=1;
            i:=b[i];
            inc(k);
            if k>2 then begin writeln('2');halt;end;
          end;
        if k=2 then m:=1;
      end;
  writeln(m);
 // close(input);close(output);
end.


可怜停机德,堪叹咏絮才。玉带林中挂,金钗雪里埋。——《红楼梦》·十二金钗判词·宝钗黛玉

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值