zoukankan      html  css  js  c++  java
  • CF1215E E. Marbles(状压dp)

    题意:

      给出n个有序排列的弹珠$(nleq 4e5)$,每个弹珠有一种颜色(不超过20种颜色),现执行操作,每次操作可以选任意一对相邻的弹珠,将其交换。要求:最终对任意颜色的弹珠,能找到l,r使$[l,r]$内所有弹珠都是该颜色并且所有该颜色弹珠都在该区间内,(即所有相同颜色的弹珠都在一起),求最少操作次数。

    解题思路:

      颜色只有20种,有点明显的状压,但是要先进行预处理操作,设cost[i][j]为把i放到j后面,i与j所交换的次数首先预处理出20种颜色互相交换的cost[i][j]。

      接下来,采用状压。位运算中,每位为1表示该颜色已经加入,为0表示没有加入,用dp[i]表示在i状态下的最少的交换次数,假设在i状态下第j种颜色已经被确定,即$((1<<j)&i)$不为0,$dp[i]=max(dp[i],sum_{k=1}^{20}cost[j][k])$,其中$(1<<k&i)=0$即第k种颜色已经确定。

      答案即为dp(1<<20-1),复杂度$O(2^{n})$

      最后贴上代码。

    #include<bits/stdc++.h>
     
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <int,int> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define de(x) cout<< #x<<" = "<<x<<endl
    #define dd(x) cout<< #x<<" = "<<x<<" "
    #define mes(a,b) memset(a,b,sizeof a)
    const ll inf=1e18;
    const int maxn=25;
     
    vector <int> v[maxn];
    ll cost[maxn][maxn];
    ll dp[1<<20];
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n;
        mes(cost,0);
        rep(i,0,n)
        {
            int x;
            cin>>x;
            v[x].pb(i);
        }
        rept(i,1,20)//i is in front of j
        {
            rept(j,1,20)
            {
                if(i==j) continue;
                int p=-1;
                rep(k,0,v[i].size())
                {
                    while(p+1<v[j].size()&&v[j][p+1]<v[i][k]) p++;
                    cost[i][j]+=p+1;
                }
            }
        }
        dp[0]=0;
        rep(i,1,(1<<20))
        {
            dp[i]=inf;
            rep(j,0,20)
            {
                if(i&(1<<j))
                {
                    int k=i-(1<<j);
                    long long plus=0;
                    rep(l,0,20)
                    {
                        if((1<<l)&k)
                            plus+=cost[j+1][l+1];
                    }
                    dp[i]=min(dp[i],plus+dp[k]);
                }
            }
        }
        cout<<dp[(1<<20)-1]<<"
    ";
        return 0;
    }
  • 相关阅读:
    写Log日志的方法 减少插件引用
    操作文件常用的方法
    Git常用命令
    JS
    js
    BUG++
    mysql点滴记录 二 (MySql经典练习题)
    mysql点滴记录 一 (创建表结构 & 构建测试数据)
    TCPDF
    Docker-命令
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/12397965.html
Copyright © 2011-2022 走看看