[Codeforces1238E]Keyboard Purchase

題意

一個只包含前mm個字母的長度爲nn的字符串ss

對於一個包含前mm個字母的排列,設poscpos_c表示字母cc在排列中的位置

求一個排列使得i=2nposs[i]poss[i1]\sum_{i=2}^n|pos_{s[i]}-pos_{s[i-1]}|最小,輸出最小值即可


題解

cntx,ycnt_{x,y}表示字母x,yx,y有多少次相鄰(特別的cntx,x=0cnt_{x,x}=0

那麼就是最小化i=1mj=1i1cnti,jposiposj\sum_{i=1}^m\sum_{j=1}^{i-1}cnt_{i,j}|pos_i-pos_j|

注意到mm只有2020,可以考慮狀壓,設全集爲TT

對於一個集合ss,假設新加入一個字母xx,我們就把xx放在排列的s|s|位(由於是絕對值的差,全員的位置都1-1不影響結果)

可以證明這樣做是能取到所有最優情況的,因爲擴展到集合ss時,ss中每個字母放在最後的情況都會被算到

那麼把xx加入集合的代價爲yscnty,x(sposy)\sum_{y\in s}cnt_{y,x}(|s|-pos_y)

((注意此時是無法暴力存下位置然後枚舉轉移的,因爲可能會有很多總代價相同的排列,時間複雜度可以達到O(m32m+n)O(m^32^m+n)))

sums,x=yscnty,xsum_{s,x}=\sum_{y\in s}cnt_{y,x},這個是可以預處理出來的

主要考慮後面減去的posypos_y如何轉化

而由於我們無法存下位置,所以只能在xx上面想如何處理

假設再新加入一個字母zz,則其代價中與xx有關的就只有cntz,xposx-cnt_{z,x}pos_x這一項

而此時posx=spos_x=|s|,其中zTsz\in T-s

所以對於所有的zzxx的貢獻和就爲s×sumTs,x-|s|\times sum_{T-s,x}

所以yscntx,y(s+1posy)\sum_{y\in s}cnt_{x,y}(|s|+1-pos_y)就可以等價轉化爲s×(sums,xsumTs,x)|s|\times(sum_{s,x}-sum_{T-s,x})

於是設fsf_s表示集合ss的等價代價的最小和,那麼

fsx=minxsfs+s×(sums,xsumTs,x)f_{s|x}=\min_{x\notin s}f_{s}+|s|\times(sum_{s,x}-sum_{T-s,x})

時間複雜度O(m2m+n)O(m2^m+n)

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5,M=25,S=(1<<21)+5;
typedef long long ll;
int n,m,T,Mi[M],cnt[M][M];
int f[S],Log[S],cntBit[S],sumC[S][M];
char s[N];
int main(){
	#ifndef ONLINE_JUDGE
		file("s");
	#endif
	scanf("%d %d\n",&n,&m);
	gets(s+1);T=(1<<m)-1;
	fp(i,2,n)
		++cnt[s[i]-'a'][s[i-1]-'a'],
		++cnt[s[i-1]-'a'][s[i]-'a'];
	fp(i,0,m)cnt[i][i]=0;
	Mi[0]=1;Log[0]=-1;
	fp(i,1,m-1)Mi[i]=Mi[i-1]<<1;
	fp(s,1,T){
		Log[s]=Log[s>>1]+1;
		cntBit[s]=cntBit[s>>1]+(s&1);
		int y=Log[s&(-s)];
		fp(x,0,m-1)sumC[s][x]=sumC[s^Mi[y]][x]+cnt[x][y];
	}
	memset(f,127,sizeof f);f[0]=0;
	fp(s,0,T)fp(i,0,m-1)if(!(s&Mi[i]))
		cmin(f[s|Mi[i]],f[s]+cntBit[s]*(sumC[s][i]-sumC[T^s][i]));
	printf("%d\n",f[T]);
return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章