Codeforces 1215E. Marbles

Posted lltyyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 1215E. Marbles相关的知识,希望对你有一定的参考价值。

传送门

注意到 $a$ 的值的数量并不大,考虑状压 $dp$

设 $f[S]$ 表示此时确定的数集合为 $S$ ,且按某种顺序从数列开头排列完成的最小交换次数

那么每个状态枚举最后一个填的数,加上代价后,取最小值即可

现在最大的问题是,代价怎么算...???

注意到我们每次交换相邻的两个数,这两个数和其他的数的相对位置是不变的(这个我认为是整题最关键的地方)

就是说在最优情况下,我们把数字 $x$ 统一交换到某个段时,产生的代价即为这个数原本每个位置和此时这个位置之前还没确定的数的数量....

讲得好绕啊,看代码比较好理解吧............

复杂度算一下达到了 $1e8$ 级别,但是 $CF$ 跑得快,这一题时限又长,所以很稳

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
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<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=4e5+7,M=(1<<20)+7;
int n,a[N],b[N],cnt[27];
ll cst[27][27],f[M];
// cst[i][j] 表示把值i统一交换到值j之前的代价
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=20;j++)
            cst[a[i]][j]+=cnt[j];
        cnt[a[i]]++;
    }
    int mx=(1<<20)-1;
    memset(f,0x3f,sizeof(f)); f[0]=0;
    for(int i=1;i<=mx;i++)
        for(int j=0;j<20;j++)
        {
            if(!((i>>j)&1)) continue;
            ll t=0;
            for(int k=0;k<20;k++)
            {
                if((i>>k)&1) continue;
                t+=cst[j+1][k+1];//代价和为 和此时还没确定的所有数交换的代价
            }
            f[i]=min(f[i],f[i^(1<<j)]+t);
        }
    printf("%lld
",f[mx]);
    return 0;
}

 

以上是关于Codeforces 1215E. Marbles的主要内容,如果未能解决你的问题,请参考以下文章

codeforces E. Marbles(状压dp)

ARC_086_E Smuggling Marbles

AtCoderARC086 E - Smuggling Marbles

ARC086 E Smuggling Marbles

Codeforces 1215

CF 1215 B The Number of Products(思维题)