【Codeforces 1215E】Marbles(状压DP)

题目链接

想不出来…然而contest的时候一大堆人过掉了…qwq

颜色数只有 m = 20 m=20 m=20。我那时的想法,设 f [ S ] f[S] f[S]表示把集合 S S S排到最前面时的最小交换数,将这个集合排前面,无论集合内顺序如何,后面剩余部分的相对顺序不变,所以再算一个 g [ S ] [ i ] g[S][i] g[S][i]表示单独考虑 S S S集合,把 i i i排到最前面的最小交换数。然后一直到比赛结束都想不出怎么算 g g g

然而 g g g是很好算的…设 P [ i ] [ j ] P[i][j] P[i][j]表示把所有 i i i j j j抽出来(相对顺序不变),然后让 j j j全排到 i i i前面的最小交换次数。显然每个 j j j需要的交换次数就是它之前的 i i i的个数, O ( n m ) O(nm) O(nm)就可以求出。然后 g [ S ] [ i ] g[S][i] g[S][i]也好算了,就是 s i g m a ( P [ j ] [ i ] ) , j ∈ S sigma(P[j][i]),j∈S sigma(P[j][i])jS

总复杂度 O ( 2 m ∗ m 2 + n m ) O(2^m * m^2 + nm) O(2mm2+nm)

const int N=400005;
const int S=20;
const int M=(1<<S)-1;
const LL INF=1000000000000000000LL;
int n;LL f[(1<<S)+5],g[S+5][S+5],p[S+5];
int main( )
{
  int i,j,k;LL x,y;
  read(n);
  for(i=1;i<=n;i++)
    {
      k=read( )-1;
      for(j=0;j<S;j++) if(k!=j) g[k][j]+=p[j];
      p[k]++;
    }
  for(i=1;i<=M;i++)
    {
      x=INF;
      for(j=0;j<S;j++)
		if((1<<j)&i)
		  {
		    for(y=0,k=0;k<S;k++)
		      if((1<<k)&i) y+=g[j][k];
		    x=min(x,f[i^(1<<j)]+y);
		  }
	      f[i]=x;
    }
  cout<<f[M];
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值