标签:
咱家今天作业有点多,就刷了一道,不开森
题目简述:给你两个长度为n的序列,你可以每次交换其中一个序列中两个数的位置,问你最少需要多少次交换是两序列的对应项的差的和最小
我都把题目简化成这样了,就应该很明显了吧,假设我们把两个序列都sort掉此时的和是最小的,至于为什么,看下面:
(1)设序列只有两个数分别是a,b;c,d;且c < d,a < b
令S1=(a-c)(a-d)+(b-d)(b-d),S2=(a-d)(a-d)+(c-b)(c-b),则:
S1-S2=2ad+2bc-2ac-2bd=2a(d-c)+2b(c-d)=2(d-c)(a-b)。由已知条件易知S1 < S2。
(2)由数学归纳法可以知道假设k个都是按序拍距离最小,第K+1项也一定是满足这样的顺序才能保证最小。
我们在struct中存下它的值已经原来的位置,sort a,b ,即目标状态,再用rank记录下对应点的关系,然后就是BIT+逆序对啦
那么问题就简化到了模板上,不要问我逆序对是什么,自己去百度吧
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; const int mod = 1e8 - 3; const int Size = 1e5 + 5; struct data{ int v,num; }; int n,ans; int bit[Size],rank[Size]; data a[Size],b[Size]; bool cmp(data,data);void updata(int); int ask(int); int main(){ scanf("%d",&n); for (int i = 1;i <= n; ++i) scanf("%d",&a[i].v); for (int i = 1;i <= n; ++i) scanf("%d",&b[i].v); for (int i = 1;i <= n; ++i) a[i].num = b[i].num = i; sort(a + 1,a + n + 1,cmp); sort(b + 1,b + n + 1,cmp); for (int i = 1;i <= n; ++i) rank[a[i].num] = b[i].num;for (int i = 1;i <= n; ++i){ updata(rank[i]); ans = (ans + i - ask(rank[i])) % mod; } printf("%d\n",ans); return 0; } bool cmp(data a,data b){ return a.v < b.v; }void updata(int x){ for (int i = x;i <= n; i += i & -i) ++bit[i]; } int ask(int x){ int ans = 0; for (int i = x;i; i -= i & -i) ans += bit[i]; return ans; }
标签:
原文地址:http://www.cnblogs.com/GENEVE/p/4808318.html