E. Marbles

题目1

题意:

    有n个数,每个数都有一种颜色。每次操作可以交换两个元素的位置,要求使得相同颜色的元素连续排列的最小次数。
     2 n 4 1 0 5 , 1 a i 20 2≤n≤4*10^5,1≤a_i≤20

分析:

    看到颜色数只有20,就可以往网络流或者状压方向去想。分析过后可以想出状压的解法。压缩颜色为状态,0代表这个颜色尚未处理,1代表这个颜色已经处理好了。处理好的颜色统一放到左边。
    考虑转移,对于一个状态,它可以由当前状态的某一个1变为0的那个状态转移过来。代价是多少呢?就是当前那个1对应颜色前的那些未被处理的颜色个数,即对应的状态为0的那些颜色。对于计算这些颜色,我们可以预处理一下,num[i][j]表示在i颜色前的颜色j的数量。用这些来算代价,转移即可。

#include <iostream>
using namespace std;

typedef long long ll;

int a[400005];
ll cnt[30],num[30][30];
ll dp[1<<20];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		for (int j = 0; j < 20; j++)
		{
			num[a[i]-1][j] += cnt[j];
		}
		cnt[a[i]-1] ++;
	} 
	for (int i = 1; i < (1<<20); i++)
	{
		dp[i] = 1e18;
		for (int j = 0; j < 20; j++)
		{
			if( ((i >> j) & 1) == 0 ) continue;
			ll temp = 0;
			for (int k = 0; k < 20; k++)
			{
				if( (i>>k) & 1 ) continue;
				temp += num[j][k];
			}
			dp[i] = min(dp[i],dp[i^(1<<j)]+temp);
		}
	}
	cout << dp[(1<<20)-1] << '\n';
	return 0;
}

发布了103 篇原创文章 · 获赞 6 · 访问量 7020

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/104738057