题目链接   http://acm.hdu.edu.cn/showproblem.php?pid=5900

题意:给出序列$A_{i}.key$和$A_{i}.value$,若当前相邻的两个数$A_{i}.key$和$A_{i+1}.key$的最大公约数大于1,则可以把这两个数消去,同时消去$A_{i}.value$和$A_{i+1}.value$,每次消去得到的分数为$A_{i}$和$A_{i+1}$的value值,问最大可能得分。

注意:当$A_{i}$和$A_{i+1}被$消去后,$A_{i-1}$和$A_{i+2}$成为了新的相邻的数。若符合条件则可以继续消去。

思路:很明显是区间DP,但是我比赛中如何也A不了。原因有两个:1.没有注意到位运算的低优先级。2.没有把所有情况考虑清楚。

设$f[i][j]$为从第$i$个数到第$j$个数所能得到的最大得分,$j-i+1$从2开始依次枚举,最后枚举到$f[1][n]$(考虑DP的无后效性)

分类讨论即可。先考虑不合并的情况,则$f[i][j]$被$f[i][k]+f[k + 1][j]$依次更新。

          再考虑合并的情况$f[i][j]$可以被$f[i][k] + a[k + 1] + a[k + 2] + f[k +3][j]$更新。

          特殊情况讨论:当$a[i + 1]$到$a[j - 1]$中所有的数都可以被消去,则$a[i]$和$a[j]$作为相邻的数也可以被消去。这种情况的讨论非常重要!!!

      代码送上

 #include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional> using namespace std; #define REP(i,n) for(int i(0); i < (n); ++i)
#define rep(i,a,b) for(int i(a); i <= (b); ++i)
#define dec(i,a,b) for(int i(a); i >= (b); --i)
#define for_edge(i,x) for(int i = H[x]; i; i = X[i]) const int N = + ;
const int M = + ;
const int Q = + ;
const int A = + ; typedef long long LL; LL f[Q][Q];
bool c[Q][Q];
bool ret[Q][Q];
int T;
int n;
LL a[Q], b[Q];
LL gcd(LL a, LL b){ return b == ? a : gcd(b, a % b); } int main(){
scanf("%d", &T);
while (T--){
scanf("%d", &n);
memset(a, , sizeof a);
memset(b, , sizeof b);
memset(c, false, sizeof c);
memset(ret, false, sizeof ret);
memset(f, , sizeof f);
rep(i, , n) scanf("%lld", a + i);
rep(i, , n) scanf("%lld", b + i);
rep(i, , n - ) rep(j, i + , n) if (gcd(a[i], a[j]) != ) c[i][j] = true;
rep(i, , n - ) if (gcd(a[i], a[i + ]) > ) ret[i][i + ] = true;
for (int len = ; len <= n; len += ){
rep(i, , n - len + ){
int j = i + len - ;
bool flag = false;
if (c[i][i + ] && ret[i + ][j]) flag = true;
if (c[j - ][j] && ret[i][j - ]) flag = true;
if (c[i][j] && ret[i + ][j - ]) flag = true;
for (int k = i + ; k <= j - ; k += ) if (ret[k][k + ] && ret[i][k - ] && ret[k + ][j]){ flag = true; break;}
if (flag) ret[i][j] = true;
}
} rep(i, , n - ) if (c[i][i + ]) f[i][i + ] = b[i] + b[i + ];
rep(i, , n - ) f[i][i + ] = max(f[i][i + ], f[i + ][i + ]);
rep(len, , n){
rep(i, , n - len + ){
int j = i + len - ;
rep(k, i, j) f[i][j] = max(f[i][j], f[i][k] + f[k + ][j]);
if (len % == ){ if (ret[i + ][j - ] && c[i][j]) f[i][j] = max(f[i][j], b[i] + b[j] + f[i + ][j - ]); }
f[i][j] = max(f[i][j], f[i + ][j]);
f[i][j] = max(f[i][j], f[i][j - ]);
if (c[i][i + ]) f[i][j] = max(f[i][i + ] + f[i + ][j], f[i][j]);
if (c[j - ][j]) f[i][j] = max(f[j - ][j] + f[i][j - ], f[i][j]);
rep(k, i + , j - ) if (c[k][k + ]) f[i][j] = max(f[i][j], f[i][k - ] + f[k][k + ] + f[k + ][j]);
}
}
printf("%lld\n", f[][n]); } return ; }

HDU 5900 QSC and Master (区间DP)的更多相关文章

  1. HDU 5900 QSC and Master 区间DP

    QSC and Master Problem Description   Every school has some legends, Northeastern University is the s ...

  2. 2016 年沈阳网络赛---QSC and Master(区间DP)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5900 Problem Description Every school has some legend ...

  3. HDU 5900 QSC and Master

    题目链接:传送门 题目大意:长度为n的key数组与value数组,若相邻的key互斥,则可以删去这两个数同时获得对应的两 个value值,问最多能获得多少 题目思路:区间DP 闲谈: 这个题一开始没有 ...

  4. HDU 5900 - QSC and Master [ DP ]

    题意: 给n件物品,有key和value 每次可以把相邻的 GCD(key[i], key[i+1]) != 1 的两件物品,问移除的物品的总value最多是多少 key : 1 3 4 2  移除3 ...

  5. hdu 4597 + uva 10891(一类区间dp)

    题目链接:http://vjudge.net/problem/viewProblem.action?id=19461 思路:一类经典的博弈类区间dp,我们令dp[l][r]表示玩家A从区间[l, r] ...

  6. HDU 2476 String painter (区间DP)

    题意:给出两个串a和b,一次只能将一个区间刷一次,问最少几次能让a=b 思路:首先考虑最坏的情况,就是先将一个空白字符串刷成b需要的次数,直接区间DP[i][j]表示i到j的最小次数. 再考虑把a变成 ...

  7. hdu_5900_QSC and Master(区间DP)

    题目链接:hdu_5900_QSC and Master 题意: 有n个数,每个数有个key值,有个val,如果相邻的两个数的key的gcd大于1那么就可以得到这两个数的val的和,现在问怎么取使得到 ...

  8. HDU 4597 Play Game(区间DP(记忆化搜索))

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597 题目大意: 有两行卡片,每个卡片都有各自的权值. 两个人轮流取卡片,每次只能从任一行的左端或右端 ...

  9. HDU 5151 Sit sit sit 区间DP + 排列组合

    Sit sit sit 问题描述 在一个XX大学中有NN张椅子排成一排,椅子上都没有人,每张椅子都有颜色,分别为蓝色或者红色. 接下来依次来了NN个学生,标号依次为1,2,3,...,N. 对于每个学 ...

随机推荐

  1. HTTP协议中POST方法和GET方法有那些区别?

    GET用于向服务器请求数据,POST用于提交数据 GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作 GET请求的URL有长度限制1k ...

  2. 《Cracking the Coding Interview》——第14章:Java——题目4

    2014-04-26 19:02 题目:解释下C++里模板和java里泛型的区别? 解法:我很少用java,属于连语法都不过关的程度.所以这个题还真没法详细答,查了些资料以后写了以下几点. 代码: / ...

  3. 《Cracking the Coding Interview》——第11章:排序和搜索——题目5

    2014-03-21 21:37 题目:给定一个字符串数组,但是其中夹杂了很多空串“”,不如{“Hello”, “”, “World”, “”, “”, “”, “Zoo”, “”}请设计一个算法在其 ...

  4. 《算法》C++代码 Dijkstra

    单源最短路,复杂度是O(N²),堆优化的是O(NlogN).基本思想是贪心,每次都加入一个当前最近的点,可以证明每次当时最近的点就是当前最短的路径.因此,所有点都加入之后,起点到所有点的最短路径就都求 ...

  5. asp.net 身份验证-Form 身份验证

    一. .net身份验证简介 1.身份验证就是检测用户是否登录及所访问的资源是否有权限.当我们在访问一个受保护网络资源时,往往需要输入用户名.密码信息,或通过其他证书.第三方身份验证等方式.验证(Aut ...

  6. Python 协程与事件循环

    Table of Contents 前言 协程 async & await 事件循环 asyncio 的事件循环 结语 参考链接 前言 Python 标准库 asyncio 是我目前接触过的最 ...

  7. 孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归

    孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Python函数非常的灵活,今天学习了python函数的以 ...

  8. 简述Shiro验证过程

    如果让我们自己实现用户登录验证我们都需要哪些步骤? 很简单,根据用户提供的账号从数据库中查询该账户的密码以及一些其他信息,然后拿这个密码与用户输入的密码相比较,因为保存在数据库中的密码一般是经过加密的 ...

  9. linux的screen常用命令使用记录

    新建screen screen 或者 screen -S name - name用于指定一个screen的名字,默认系统随机 暂时退出当前screen ctrl + a + d - 同时按住这三个键即 ...

  10. NodeJs04

    REST API的设计 前言 客户端通过请求URL,传递参数,去获取指定的数据,这就是API(ApplicationProgramInterface). API是前端和客户端操作后端数据的一种方式,一 ...