sjtu1590 强迫症

Description

BS96发布了一套有\(m\)个band柄绘的新badge,kuma先生想要拿到04的badge于是进行了抽抽抽。
kuma先生一共抽了\(n\)个badge。他把所有的badge排成一排来统计战果,出于强迫症他希望把所有相同band的badge放在一起。
kuma先生整理badge的方法是交换\(2\)个相邻的badge,现在他想知道他最少交换多少次可以达成目的。

Input

有多组数据,第一行一个数\(T\)表示数据组数,接下来每组数据有\(2\)行。
第一行两个数\(n,m\)
第二行\(n\)个数,表示每个badge的band编号。

Output Format

对于每组数据输出一行,形如”Case #X:Y”。X为数据组数,从\(1\)开始,\(Y\)为最少的交换次数。

Sample Input

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

Sample Output

Case #1: 1
Case #2: 6
Case #3: 5

Hints

\(40\%\), \(n \le 100, m \le 6\)
\(70\%\), n \le 1000, m \le 14
\(100\%\), n \le 100000, m \le 18

首先确定了最后次序之后,这个过程就是一个冒泡排序,最少交换次数即为逆序对数目。于是这道题目便变成了一道排列dp题目。我们可以用状态压缩dp来解决。
\(f[i]\)为状态为\(i\)时的最少逆序对数目。这个状态表示若\(a\)在集合\(i\)中,则\(a\)的最终位置已经确定排在前面一块。现在考虑我们将一个不在集合中的元素\(b\)加入集合中,我们只需要考虑\(b\)对逆序对的贡献,由于集合中已有元素最后都会放在\(b\)的前面,所以我们只需要计算在原数组中有多少\((p,q),q>p\),其中\(A_p = b,A_q \in i\)。对于特定的\(a,b\),这个贡献是可以预处理的。于是算法复杂度\(O(TM^22^M)\)

#include
#include
#include
#include
using namespace std;

typedef long long ll;
#define maxn (100010)
#define maxm (20)
int T,N,M,A[maxn],suf[maxm][maxn],tmp[maxm]; ll f[1<= '0'&&ch <= '9')&&ch != '-');
    if (ch == '-') F = -1,ch = getchar();
    do ret = ret*10+ch-'0',ch = getchar(); while (ch >= '0'&&ch <= '9');
    return F*ret;
}
     
inline void ready()
{
    for (int i = 1;i <= N;++i) suf[A[i]][i] = 1;
    for (int i = N-1;i;--i) for (int j = 1;j <= M;++j) suf[j][i] += suf[j][i+1];
    for (int i = 1;i <= N;++i)
        for (int j = 1;j <= M;++j)
            cor[A[i]][j] += (ll)suf[j][i];
}
          
inline void init()
{
    memset(vis,false,1< sum) f[i|(1<

转载于:https://www.cnblogs.com/mmlz/p/6172124.html

你可能感兴趣的:(sjtu1590 强迫症)