传送门

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('\n');
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。

【DP】【CF31E】 TV Game的更多相关文章

  1. T2980 LR棋盘【Dp+空间/时间优化】

    Online Judge:未知 Label:Dp+滚动+前缀和优化 题目描述 有一个长度为1*n的棋盘,有一些棋子在上面,标记为L和R. 每次操作可以把标记为L的棋子,向左移动一格,把标记为R的棋子, ...

  2. 【10.3校内测试【国庆七天乐!】】【DP+组合数学/容斥】【spfa多起点多终点+二进制分类】

    最开始想的暴力DP是把天数作为一个维度所以怎么都没有办法优化,矩阵快速幂也是$O(n^3)$会爆炸. 但是没有想到另一个转移方程:定义$f[i][j]$表示每天都有值的$i$天,共消费出总值$j$的方 ...

  3. 【DP+树状数组】BZOJ1264-[AHOI2006]基因匹配Match

    [题目大意] 给定n个数和两个长度为n*5的序列,两个序列中的数均有1..n组成,且1..n中每个数恰好出现5次,求两个序列的LCS. [思路] 预处理每个数字在a[i]中出现的五个位置.f[i]示以 ...

  4. BZOJ1079 [SCOI2008]着色方案 【dp记忆化搜索】

    题目 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+-+ck=n.相邻两个木块涂相同色显得很难看 ...

  5. 【DP|多重背包可行性】POJ-1014 Dividing

    Dividing Time Limit: 1000MS Memory Limit: 10000K Description Marsha and Bill own a collection of mar ...

  6. COGS 862. 二进制数01串【dp+经典二分+字符串】

    862. 二进制数01串 ★   输入文件:kimbits.in   输出文件:kimbits.out   简单对比 时间限制:1 s   内存限制:128 MB USACO/kimbits(译 by ...

  7. CodeForces - 597C Subsequences 【DP + 树状数组】

    题目链接 http://codeforces.com/problemset/problem/597/C 题意 给出一个n 一个 k 求 n 个数中 长度为k的上升子序列 有多少个 思路 刚开始就是想用 ...

  8. hihocoder1475 数组分拆【DP+前缀和优化】

    思路: DP[ i ] 代表以 i 结尾的方案数. dp[i] += sum[i] - sum[j - 1] != 0 ? dp[j] : 0 ; 对于100%的数据,满足1<=N<=10 ...

  9. SPOJ130 【DP·背包选取特性】

    题意: 给你n个任务,每个任务有一个起始时间,持续时间,一个权值: 问你怎么分配得到最大值 思路: 数据好大..百度了一发意识到自己好菜啊!背包的特性. dp[i]代表前 i 个能构成的最大值. 对于 ...

  10. lightoj1145 【DP优化求方案】

    题意: 有一个k面的骰子,然后问你n个骰子朝上的面数字之和=s的方案: 思路: dp[i][j] 代表 前 i 个骰子组成 j 有多少种方案: 显然 dp[i][j] = dp[i - 1][j - ...

随机推荐

  1. selenium+Java,xpath定位方法详解(搬运留存)

    用xpath绝对路径比较费事费力,还容易报错,下面几种模糊定位比较灵活好用 driver.findElement(By.xpath("//*[@id='J_login_form']/dl/d ...

  2. Android 不同分辨率下调整界面

    Android Settings中有修改Disaply size的界面,通过修改Display size,能够修改屏幕分辨率. 由于修改了屏幕分辨率,有可能导致同一界面在不同的分辨率下显示出错(内容显 ...

  3. PHPCMS如何让手机站点取消浏览大图直接加载原图

    一.然后找到phpcms\modules\wap\functions\global.func.php 文件,找到相关代码,如下图: return '<img src="'.thumb( ...

  4. JavaScript学习笔记(三)——对象

    第四章 理解对象 1 说明 对象的状态:属性,行为:方法: 对象定义放在花括号内: 用冒号分隔属性名和属性值: 用逗号分隔属性名和属性值对,包括方法: 最后一个属性值后面不加逗号: 属性名可以是任何字 ...

  5. leetcode26_C++删除排序数组中的重复项

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...

  6. Paper Reading - Long-term Recurrent Convolutional Networks for Visual Recognition and Description ( CVPR 2015 )

    Link of the Paper: https://arxiv.org/abs/1411.4389 Main Points: A novel Recurrent Convolutional Arch ...

  7. 算法笔记(c++)--01背包问题

    算法笔记(c++)--经典01背包问题 算法解释起来太抽象了.也不是很好理解,最好的办法就是一步步写出来. 背包问题的核心在于m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+ ...

  8. JUnit initializationError错误

    一.JUnit Test 测试 initializationError错误 MyMaincom.test.sunc.MyMaininitializationError(com.test.sunc.My ...

  9. 软银集团和共享办公空间公司WeWork在日本成立合资公司

    [TechWeb报道]7月18日消息,据国外媒体报道,软银集团和共享办公空间公司WeWork联合宣布,在日本成立合资公司WeWork Japan. 该合资公司将在日本开设联合办公空间,于明年初在东京设 ...

  10. loadrunner socket协议问题归纳(5)

    获取服务器的返回值,可以用web_reg_save_param函数,该参数最好放到: 语法: int web_reg_save_param(const char *ParamName, <lis ...