zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    this.$route和this.$router的区别
    HTTP请求方式中get和post的区别
    如何使用NPM?CNPM又是什么?
    javascript通过navigator.userAgent识别各种浏览器
    用JS添加和删除class类名
    前端布局神器display:flex
    强大的display:grid
    自动化测试的那些事儿
    selenium家族发展史
    第八章、函数进阶之字典生成式与匿名函数
  • 原文地址:https://www.cnblogs.com/vege-chicken-rainstar/p/11526722.html
Copyright © 2011-2022 走看看