M
最小内积
时间限制:1000ms 内存限制:131072kb
看到这题手推了一下,就明白应该是一个数组的最大值乘以另一个数组的最小值,再次大值乘以次小值,一次类推,这个很简单,sort一遍再相乘就好了,现在问题就在于如何求最小交换次数了,其实小弱在查阅了大量网上资料后才知道一个数组要重新排序的最少交换次数应该算出原本在数组中的根据到目标位置的环的个数(参考北航第十二届程序设计竞赛网络预赛题解:点击打开链接)再用数组个数n减去环的个数,这样就是最小的交换次数,当然这只是本题的基本算法,然后我就陷入了算法误区,我原本的思路是两个数组,一个从大到小排序,一个从小到大排序,再将两次的交换次数加起来,求出不同排序的最少交换次数,然后再把最小内积求出来输出,可是预赛的时候TLE+wrong两次之后再也不敢提交,看了题解才明白只要修改一个数组就好了,只要把一个数组的最小值交换到另一个数组的最大值地方依次类推,,然后目的地确定好之后再对这个数组进行求最少交换次数算法,整个题目就ok了,当然这里面还有个强制转换的问题,详情代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define siz 100005
using namespace std;
struct node
{
int elem;//元素
int index;//原下标
int in;//目标下标
};//结构体数组,记录数据和下标
node mp1[siz],mp2[siz];
int cmp(node a,node b)
{
return a.elem<b.elem;
}
int cmp2(node a,node b)
{
return a.elem>b.elem;
}
int cmp3(node a,node b)
{
return a.index<b.index;
}
int n;
int vis[siz];
int jiaohuan(node arr[])//求最少交换次数函数
{
int sum=0;
memset(vis,0,sizeof(vis));
for(int i=0; i<n; i++)
{
if(vis[i]==0)
{
int l=i;
int p=i;
while(1)
{
vis[p]=1;
p=arr[p].in;
if(p==l) break;
}
++sum;
}
}
return n-sum;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&mp1[i].elem);
mp1[i].index=i;
}
for(int i=0; i<n; i++)
{
scanf("%d",&mp2[i].elem);
mp2[i].index=i;
}
sort(mp1,mp1+n,cmp);
sort(mp2,mp2+n,cmp2);
for(int i=0; i<n; i++)
{
mp1[i].in=mp2[i].index;//确定目标下标
}
sort(mp1,mp1+n,cmp3);
int ans=jiaohuan(mp1);
long long int _=0;
sort(mp1,mp1+n,cmp);
for(int i=0; i<n; i++)
{
_=_+(long long)mp1[i].elem*mp2[i].elem;//强制转换
}
printf("%lld %d\n",_,ans);
}
return 0;
}
/*
10
5
2 6 8 7 5
5 4 3 2 1
*/
代码还能少用一个sort,用三个sort就已经足够了。