【题解】Codeforces1238E. Keyboard Purchase 状压DP/子集DP

给定n(1e5),m(20),一个长为n,字符集在m以内的字符串S。
现在要求找到1到m的一个排列,使得 Σ ∣ P S i − P S i + 1 ∣ \Sigma |P_{S_i}-P_{S_{i+1}}| ΣPSiPSi+1最小,其中 P c P_c Pc表示字符c在排列中出现的位置。求最小代价。


猜到是dp->猜到是状压dp->算法假了->白给80分钟,dp好菜啊,还是做的少。

首先预处理一个cnt数组, c n t [ i ] [ j ] cnt[i][j] cnt[i][j]表示字符 i i i到字符 j j j转移了多少次。
d p [ m a s k ] dp[mask] dp[mask]表示选择了mask这个子集的最小代价, d p [ 0 ] = 0 dp[0]=0 dp[0]=0
d p [ m a s k ] = m i n { d p [ m a s k ⊕ ( 1 < < i ) ] } + Σ c n t [ i ] [ j ] dp[mask] = min\{dp[mask\oplus (1<dp[mask]=min{dp[mask(1<<i)]}+Σcnt[i][j],其中 i i i取遍所有属于mask的字符, j j j取遍所有不属于mask的字符。


这样做为什么是对的呢?以下是我的理解:
d p [ m a s k ] dp[mask] dp[mask]是把属于mask的字符都堆在左边时的最小代价,而且这个代价消除了后效性。
每当把一个新字符放在最右侧后,就会将代价加上所有的已放字符和未放字符的转移次数之和。

相当于,mask内部的字符的代价已经被计算完毕,而且这些内部字符还计算过与外部字符之间的代价。来得越早,计算的次数越多。

换句话说,我可以视为把所有的内部字符都堆在一个位置上,因为由它们位置不同所产生的代价已经被计算完毕。

当新添加一个字符时,我需要把它加入到那一堆中。实际上相当于把新字符放到一堆的下一位,然后把那一堆全部朝右移动一位。而全部朝右移动一位的代价,就是堆中字符与外部字符的转移次数之和。

这样做的话,每次转移的复杂度是 O ( m 2 ) O(m^2) O(m2),但是注意到每一堆朝右移动一位的代价是固定的。我们可以在得出每个的dp值后就把这部分的转移代价也加上,也就是上文中的转移式。

此时转移复杂度 O ( m ) O(m) O(m),总复杂度 O ( n + m ⋅ 2 m ) O(n+m·2^m) O(n+m2m).


/* LittleFall : Hello! */
#include 
using namespace std; using ll = long long; inline int read();
const int M = (1<<20)+16, MOD = 1000000007;

char str[M];
int cnt[32][32];
int dp[M];
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int n = read(), m = read();
	scanf("%s", str);
	for(int i=0; i<n-1; ++i)
	{
		cnt[str[i]-'a'][str[i+1]-'a']++;
		cnt[str[i+1]-'a'][str[i]-'a']++;
	}
	memset(dp, 0x3f, sizeof(dp));
	dp[0] = 0;
	for(int mask=1; mask<(1<<m); ++mask)
	{
		for(int i=0; i<m; ++i) if(mask>>i&1)
			dp[mask] = min(dp[mask], dp[mask^(1<<i)]);
		for(int i=0; i<m; ++i) if(mask>>i&1)
		for(int j=0; j<m; ++j) if(~mask>>j&1)
			dp[mask] += cnt[i][j];
	}
	printf("%d\n",dp[(1<<m)-1] );

    return 0;
}


inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

你可能感兴趣的:(题解)