codeforces 1215 E Marbles-----状压DP

Posted vege-chicken-rainstar

tags:

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

Marbles

题意:长度4e5的数字序列,不同数字个数至多20个,每次操作可选取两个相邻数字并交换位置,现在想要使序列中所有相同数字都排列在一起,问至少需要几次操作。时限4s.

题解:由不同数字个数至多20应该想到状压DP......

? 现在假想全部排完之后的状态,根据不同数字块的位置显然有\(20!\)种情况,那么我们可以假想数字1到20是一个一个完成合并并放到数列左端的。这样的话\(DP[i]\)就表示\(i\)数位上为\(1\)的数字完成合并并丢在左边所需操作次数。

? 预处理一个\(val[i][j]\)表示把所有数字\(i\)放到所有数字\(j\)左边所需操作次数,那么很显然转移的增量就是这个数字与其他所有未完成合并的数字的\(val\)和。(好巧妙TuT)

? 复杂度:o(\(2^20*400\)).

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> pos[20];
typedef long long ll;
ll dp[1<<20],val[20][20];
int main()
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        int x;
        scanf("%d",&x);
        pos[x-1].push_back(i);
    
    for(int i=0;i<20;i++)
        for(int j=0;j<20;j++)
            if(i==j||pos[j].empty()) continue;
            for(int k=0;k<int(pos[i].size());k++)
                int x=pos[i][k];
                val[i][j]+=lower_bound(pos[j].begin(),pos[j].end(),x)-pos[j].begin();
            
        
    
    memset(dp,0x3f3f3f3f,sizeof(dp));
    dp[0]=0;
    for(int i=0;i<(1<<20);i++)
        vector<int> u;
        for(int j=0;j<20;j++)
            if((1<<j)&i) continue;
            u.push_back(j);
        
        for(int j=0;j<int(u.size());j++)
            int x=u[j];
            ll sum=0;
            for(int k=0;k<int(u.size());k++)
                if(u[k]!=x) sum+=val[x][u[k]];
            
            dp[i|(1<<x)]=min(dp[i|(1<<x)],dp[i]+sum);
        
    
    cout << dp[(1<<20)-1];
    return 0;

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

Codeforces 1215

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

博弈论 Codeforces1215D Ticket Game

Codeforces Round #585 (Div. 2) CF1215A~C

codeforces E. Marbles(状压dp)

CF 1215 D Ticket Game (博弈)