Description
给你一个长度为(2n)的数字,每次可以从左侧选一个数字,加入连接到一个数字(A)或另一个数字(B)后面。(A,B)初始为(0)。(A)与(B)必须恰好被连接(n)次。最大化(A,B)的和,输出方案
Input
第一行是(n),第二行是长度为(2n)的数字
Output
从左到右输出该数字第几位被如何处理。连接到(A)输出(H),连接到(B)输出(M)。
Hint
(1~leq~n~leq~18)
Solution
看起来像是个DP啊……
考虑如果正向DP的话,每次选择一个数,数字和增加多少依赖于之前那个数字选了多少。这显然是有后效性的,难以处理。
考虑反过来DP。
这样每次选一个数只依赖于之前选了多少位,可以直接设到状态里面。于是可以设(f_{i,j})为(A)选了(i)位,(B)选了(j)位的数字和,转移显然。
Code
#include<cstdio>
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
template <typename T>
inline void qr(T &x) {
rg char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
}
namespace IO {
char buf[120];
}
template <typename T>
inline void qw(T x,const char aft,const bool pt) {
if(x < 0) {x=-x,putchar('-');}
rg int top=0;
do {IO::buf[++top]=x%10+'0';} while(x/=10);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template <typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}
template <typename T>
inline void mswap(T &_a,T &_b) {
T _temp=_a;_a=_b;_b=_temp;
}
const int maxn = 40;
const int INF = 0x3f3f3f3f;
int n,dn;
int MU[maxn];
ll frog[maxn][maxn],ten[maxn]={1};
char s[maxn];
bool pre[maxn][maxn];
void dfs(ci,ci);
int main() {
qr(n);
scanf("%s",s+1);
dn=n<<1;
for(rg int i=dn;i;--i) MU[dn-i+1]=s[i]-'0';
for(rg int i=1;i<n;++i) ten[i]=ten[i-1]*10ll;
for(rg int i=0;i<maxn;++i) for(rg int j=0;j<maxn;++j) frog[i][j]=-INF;
frog[0][0]=0;
for(rg int i=0;i<=n;++i) {
for(rg int j=0;j<=n;++j) {
int len=i+j;
if(i) frog[i][j]=frog[i-1][j]+MU[len]*ten[i-1];
if(j) {
if(frog[i][j] < frog[i][j-1]+MU[len]*ten[j-1]) {
frog[i][j]=frog[i][j-1]+MU[len]*ten[j-1];pre[i][j]=true;
}
}
}
}
dfs(n,n);
putchar('
');
return 0;
}
void dfs(ci x,ci y) {
if((!x) && (!y)) return;
if(pre[x][y]) {putchar('H');dfs(x,y-1);}
else {putchar('M');dfs(x-1,y);}
}
Summary
在序列上的线性DP,当正向难以转移时,可以考虑反向DP。