题目链接:http://codeforces.com/problemset/problem/31/E
题意:
给你一个长度为2*n,n<=18的数字串,现在要你把这2*n个数字按序分配给两个人,每个人n个,同时每个人最后拿到的数字就是被分配数字从前往后的正常十进制数字,问你怎么分可以让两个人的和最大。
做法:
因为n的数据范围不大,所以其实很明显是个dp,dp的状态也相对比较好想,dp[i][j]代表前i个数字,有j个分配给其中一个人的最大和(我这里就分配给H了),两个人的和是i所以另一个人当前就是有i-j个数字,然后根据现在这第i个数字要分配给H还是M进行转移即可。 同时还需要记录一个前驱标志,表示这个状态在因为变大而更新是因为给了H还是M,最后再一路找回去就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=20;
int n,a[maxn*2];
//pre为0时,代表这个位置取M更好
int pre[maxn*2][maxn];
//到达第i个时,有j个是归H的最大值
ll dp[maxn*2][maxn];
ll wei[maxn];
char ans[maxn*2];
int main(){
scanf("%d",&n);
for(int i=0;i<2*n;i++){
scanf("%1d",&a[i]);
}
wei[1]=1;
for(int i=2;i<=19;i++){
wei[i]=wei[i-1]*10ll;
}
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
for(int i=0;i<2*n;i++){
//printf("%d\n",i);
for(int j=0;j<=min(n,i);j++){
if(dp[i][j]!=-1){
if(dp[i+1][j]<dp[i][j]+wei[n-(i-j)]*a[i]){
dp[i+1][j]=dp[i][j]+wei[n-(i-j)]*a[i];
pre[i+1][j]=0;
}
if(dp[i+1][j+1]<dp[i][j]+wei[n-j]*a[i]){
dp[i+1][j+1]=dp[i][j]+wei[n-j]*a[i];
pre[i+1][j+1]=1;
}
//printf(" i=%d j=%d di+1,j=%lld di+1,j+1 = %lld \n",i,j,dp[i+1][j],dp[i+1][j+1]);
}
}
}
int ctn=n*2,cth=n;
while(ctn>0){
if(pre[ctn][cth]==1){
ans[ctn]='H';
cth--;
}
else ans[ctn]='M';
ctn--;
}
ans[2*n+1]*'\0';
printf("%s\n",ans+1);
return 0;
}