题意:给你一个位数为 的数字 ,两个初始为 的数字 ,每次你可以将 中最靠左的一位在 中删除掉并接在 或者 其中一个的后面,要求整个操作结束后,必须 与 都恰好被接 次,最大化 的值,输出方案
我们考虑线性做法O(n)跑18,我们已经在A和B中放好了S的前i个数,其中A放了j个,B放了k个,那么我们对于第i+1个数,它可以放在A或B的末尾,于是我们有了状态转移方程
放数的时候注意是从最高位开始放
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define int long long
using namespace std;
const int N=100;
int n,m,dp[N][N],a[N][N],b[N][N],c[N],len;
char go[N][N][N];
char str[N<<1];
inline int read(){
int sym=0,res=0;char ch=0;
while (!isdigit(ch))sym|=(ch=='-'),ch=getchar();
while (isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return sym?-res:res;
}
void file(){
freopen("read.in","r",stdin);
freopen("write.out","w",stdout);
}
int power(int a,int x){
int res=1;
while (x){
if (x&1)res*=a;
a*=a;x>>=1;
}return res;
}
void write(int now,int x,int y,char ch){
if (now==0){
printf("%c",ch);return;
}
if (go[now][x][y]=='H')write(now-1,x-1,y,'H');
else write(now-1,x,y-1,'M');
if (now!=len)printf("%c",ch);
}
signed main(){
n=read();len=n<<1;
scanf("%s",str+1);
for (int i=1;i<=len;i++){
c[i]=str[i]-'0';
}
for (int i=1;i<=n;i++){
a[i][i]=a[i-1][i-1]+c[i]*power(10,n-i);go[i][i][0]='H';
b[i][i]=b[i-1][i-1]+c[i]*power(10,n-i);go[i][0][i]='M';
}
for (int i=1;i<=len;i++){
for (int j=max(i-n,1ll);j<=min(i-1ll,n);j++){
int k=i-j,ta=c[i]*power(10,n-j),tb=c[i]*power(10,n-k);
if (a[i-1][j-1]+ta+b[i-1][k]>b[i-1][k-1]+tb+a[i-1][j]){
a[i][j]=a[i-1][j-1]+ta;
b[i][k]=b[i-1][k];go[i][j][k]='H';
}else{
b[i][k]=b[i-1][k-1]+tb;
a[i][j]=a[i-1][j];go[i][j][k]='M';
}
}
}
write(len,n,n,' ');
return 0;
}