列表

详情


NC15570. 序列变换

描述

给定两个长度为n的序列,ai, bi(1<=i<=n), 通过3种魔法使得序列a变换为序列b,也就是ai=bi(1<=i<=n).

 

魔法1: 交换aiaji!=j

首先通过若干次的魔法1将序列a变换成序列c

 

魔法2: 对1个数乘2或者加1

魔法3: 对1个数除以2或者减1,如果是奇数,则不能除以2

ci>bi, 则只能对ci实施魔法3,若ci<bi, 则只能对ci实施魔法2. 例如ci=6, bi=4,

则可以通过对ci实施2次减1操作(魔法3)ci变为bi, 但不可以对ci除以2再加1ci变为bi,因为ci>bi, 所以不能对ci实施加1操作(魔法2).

 

小埃想通过最少的操作次数使得序列a变成序列b, 操作次数是指使用的魔法次数

输入描述

输入测试组数T,每组数据,第一行输入n,1<=n<=9,紧接着输入两行,每行n个整数,前一行为a1,a2,…,an,后一行为b1,b2,…,bn.其中1<=ai,bi<=108,1<=i<=n.

输出描述

每组数据输出一个整数,表示最少的操作次数

示例1

输入:

2
2
8 7
5 1
4
4 3 1 3
1 1 4 3

输出:

6
3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 1011ms, 内存消耗: 616K, 提交时间: 2018-04-15 15:42:53

#include<bits/stdc++.h>
using namespace std;
int t,n,x,i,a[10],b[10],p[10],q[10],r[10],o[65536],ans;
int ask(int x)
{
	if(x<65536)return o[x];
	return o[x>>16]+o[x&65535];
}
int ask(int a,int b)
{
	if(a>b)swap(a,b);
	int i=0,j=1<<30;
	for(;i<30;i++)if(b>>i>=a)j=min(j,ask(b&((1<<i)-1))+i+(b>>i)-a);
	else break;
	return j;
}
int main()
{
	scanf("%d",&t);
	for(i=1;i<65536;i++)o[i]=o[i>>1]+(i&1);
	while(t--)
	{
		scanf("%d",&n);
		for(i=1;i<=n;i++)scanf("%d",a+i);
		for(i=1;i<=n;i++)scanf("%d",b+i);
		for(i=1;i<=n;i++)p[i]=i;
		ans=1<<30;
		do
		{
			for(i=1;i<=n;i++)q[i]=p[i];
			for(i=1;i<=n;i++)r[q[i]]=i;
			x=0;
			for(i=1;i<=n;i++)if(q[i]!=i)
			{
				x++;
				r[q[i]]=r[i];
				swap(q[r[i]],q[i]);
				r[i]=i;
			}
			for(i=1;i<=n;i++)x+=ask(a[p[i]],b[i]);
			ans=min(ans,x);
		}while(next_permutation(p+1,p+n+1));
		cout<<ans<<endl;
	}
	return 0;
}

上一题