小冰的N个机器人兄弟排成一列,每个机器人有一个颜色。现在小冰想让同一颜色的机器人聚在一起,即任意两个同颜色的机器人之间没有其他颜色的的机器人。
假设任意相邻的两个机器人可以交换位置,请问最少需要多少次交换?
第一行为一个整数T,为数据组数,之后每组数据两行。
第一行为N和K,表示机器人的个数与颜色的总数。
接下来一行N个数,第i个数表示第i个机器人的颜色,取值范围为1到K。
对于每组数据输出一行,形如"Case #X: Y"。X为数据组数,从1开始,Y为最少的交换步数。
1 ≤ T ≤ 20
1 ≤ N ≤ 105
小数据
1 ≤ K ≤ 3
大数据
1 ≤ K ≤ 16
3 4 2 1 2 1 2 6 4 2 1 4 3 1 2 8 6 1 3 2 5 5 4 5 2
Case #1: 1 Case #2: 6 Case #3: 5
给定一个序列,求怎么规定各元素顺序,使逆序对数最小。
记忆化搜索,令g[nowg]表示 前几个元素状态为nowg时它们间的最小逆序对数。
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> 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 RepD(i,n) for(int i=n;i>=0;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define Forpiter(x) for(int &p=iter[x];p;p=next[p]) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define MEMI(a) memset(a,127,sizeof(a)); #define MEMi(a) memset(a,-1,sizeof(a)); #define INF (10000000001LL) #define F (100000007) #define MAXN (100000+10) #define MAXK (16+10) typedef long long ll; int a[MAXN],n,K; ll f[MAXN][MAXK],t[MAXK][MAXK]; int st[MAXN]; ll g[1<<17]; ll p2[MAXK]; void dfs(int l,int nowg) { if (g[nowg]!=-1) return; For(i,K) if (nowg&p2[i]) { ll delta=0; int v=nowg^p2[i]; For(j,K) if (v&p2[j]) { delta+=t[j][i]; } dfs(l-1,v); if (g[nowg]==-1||g[nowg]>g[v]+delta) g[nowg]=g[v]+delta; } } int main() { // freopen("C.in","r",stdin); // freopen(".out","w",stdout); p2[1]=1; Fork(i,2,16) p2[i]=p2[i-1]<<1; int T; cin>>T; For(kcase,T) { scanf("%d%d",&n,&K); For(i,n) scanf("%d",&a[i]); MEM(f) MEM(t) MEMi(g) For(i,n) For(j,K) f[i][j]=f[i-1][j]+(bool)(a[i]==j); For(i,n) { int j=a[i]; For(l,K) if (l^j) t[l][j]+=f[i][l]; } g[0]=0; dfs(K,(1<<K)-1); printf("Case #%d: %lld\n",kcase,g[(1<<K)-1]); } return 0; }