zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 74E 状态压缩dp

    Educational Codeforces Round 74E 状态压缩dp

    https://codeforces.com/problemset/problem/1238/E
    题意:
    一个字符串,你来安排一个字符排列,计算使得(sum_{i=1}^{n}|pos_{s_{i-1}}-pos_{s_{i}}|)最小。(例子里面很清楚

    思路:
    状态压缩dp,dp[111111]表示都放进去的最小值就好了,但是这个最小是什么最小就很微妙了,比如说如果我维护目前开销最小肯定是不行的,因为状态放进去的顺序是影响答案的,我们也没法转移,也就是无法取消后效性。这里的最小考虑最总贡献最小,使得单次转移只和当前前面有几个有关,我们如何做到?实际上观察表达式,应该是每对要求的字母后面的位置减前面的位置的和,也就是(cnt_{x,y}*(pos_{x}-pos_{y}))这里我们为了达到无后效性,算每个单词的“贡献”。把每个单词的加入分成两个部分,一部分是之前有多少个cnt产生了什么影响,一个是之后有多少个cnt产生了什么影响。说的混乱,可以看作是利用差分达到计算对最终答案的贡献。枚举最后插入的字符,转移方程为(dp[x]=min(dp[x],popcount(new\_x)*(sum_{jin new\_x}cnt_{i,j}-sum_{j otin new\_x}cnt_{i,j})))具体看代码就好了。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define X first
    #define Y second
    #define PB push_back
    #define LL long long
    #define pii pair<int,int>
    #define MEM(x,y) memset(x,y,sizeof(x))
    #define bug(x) cout<<"debug "#x" is "<<x<<endl;
    #define FIO ios::sync_with_stdio(false);
    #define ALL(x) x.begin(),x.end()
    #define LOG 20
    const int inf =0x3f3f3f3f;
    const int maxn =(1<<20)+7;
    int dp[maxn];
    map<int,int> h;
    int sum[maxn][22];
    int cnt[22][22];
    int n,m;
    string s;
    int lower_bit(int x){return x&-x;};
    
    int get_sum(int x,int i){
        if(sum[x][i]!=-1)return sum[x][i];
        if(x==0) return sum[x][i]=0;
        sum[x][i]=get_sum(x&(x-1),i)+cnt[h[lower_bit(x)]][i];
        return sum[x][i];
    }
    
    int DP(int x){
        if(dp[x]!=-1) return dp[x];
        if(x==0)return dp[x]=0;
        int t=x;
        dp[x]=inf;
        for(int i=0;i<m;i++){
            if(x&(1<<i)){
                int p=x^(1<<i);
                int q=x^((1<<m)-1);
                dp[x]=min(dp[x],DP(p)+__builtin_popcount(p)*(get_sum(p,i)-get_sum(q,i)));
            }
        }
        return dp[x];
    }
    
    int main(){
        FIO;
        cin>>n>>m>>s;
        MEM(dp,-1);MEM(sum,-1);
        for(int i=0;i<m;i++) h[1<<i]=i;
        for(int i=1;i<n;i++){
            ++cnt[s[i] - 'a'][s[i - 1] - 'a'];
    		++cnt[s[i - 1] - 'a'][s[i] - 'a'];
        }
        cout<<DP((1<<m)-1)<<endl;
        return 0;
    }
    
    
    
  • 相关阅读:
    考研岁月
    sklearn 翻译笔记:KNeighborsClassifier
    网站不让复制的办法
    关于VMware Workstation 15 Player 虚拟机安装Windows系统却无法安装vmware tools的解决
    今天真是太傻了
    GoogleHacking相关技巧
    判断ARP欺骗
    Linux各个文件及其含义
    小白的开始—转一篇Linux系统入门的文章
    课时39.细线表格(理解)
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/11655526.html
Copyright © 2011-2022 走看看