【狀壓DP】Educational Codeforces Round 74 (Rated for Div. 2) - E. Keyboard Purchase

題目鏈接https://codeforces.com/contest/1238/problem/E


題意

給出一個由m個小寫字母組成的長度爲n的字符串(m<=20,n<=1e5),另外對這m個字符構造出一個序列,序列內兩兩字符的座標差值是兩個字符的距離,問從左到右走字符串的每一個字符,距離最小是多少。


題解

狀壓dp[s]dp[s]代表已經確定了狀態爲ss的字符放在最左邊的情況,狀態轉移方程可以表示爲:

if(s&(1<<i)) dp[s]=min(dp[s],dp[s^(1<<i)]+tmp);

tmptmp爲在當前狀態ss內的字符與不在ss內的字符在原串相鄰的對數,ii代表這個字符放在所有已枚舉的字符的最右邊。這樣子的dpdp可以不用管後面的情況,也能計算出貢獻,好酷的dp…


#include<bits/stdc++.h>
using namespace std;
const int N=2e6+7;
const int inf=1e9;
int n,m;
int mp[30][30];
int dp[N];
char s[N];
int main(){
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len-1;i++){
        int u=s[i]-'a',v=s[i+1]-'a';
        mp[u][v]++;mp[v][u]++;
    }
    dp[0]=0;
    for(int s=1;s<(1<<m);s++){
        dp[s]=inf;
        int tmp=0;
        for(int i=0;i<m;i++){
            if(!(s&(1<<i))) continue;
            for(int j=0;j<m;j++){
                if((s&(1<<j))) continue;
                tmp+=mp[i][j];
            }
        }
        for(int i=0;i<m;i++){
            if(s&(1<<i)) dp[s]=min(dp[s],dp[s^(1<<i)]+tmp);
        }
    }
    printf("%d\n",dp[(1<<m)-1]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章