codeforces GYM 100792H
2015-11-10 21:52
561 查看
新地址链接
题意:给出n个1个字节的数(1<=n<=100000),用16进制的形式给出,每个数的范围00-FF,
找出一个子序列s, 使得0^s[0]+1^s[1]+2^s[2]+…k^s[k]的和最大,输出这个最大值。
dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+(arr[i]^j))
dp[i][j]:代表前i个数一共选了j个数能得到的最大和。但是,这样时间复杂度和空间复杂度都为1e10,
明显需要优化
,即第n
个数,选还是不选?如果选,应该让他在子序列对应的位置为多少(即子序列的长度),
仔细想想,可以明确,第n个数一定要选,[因为:如果没有选最后一个数的话,假设,
我们的最终选的子序列为s[0],s[1],s[2]…s[k], 答案假设为ans, 如果我们把第n个数加进去
的话,那么最终的答案为ans+(a
^(k+1)),由于所有的数都为正数,所以这个答案一定>=不选第
n个数的答案], 那么如果选第n个数的话,假设最终子序列的长度为k的话,应该让k为多大合适呢?
k是不是越大越好呢?首先明确:k不是越大越好,。假设有这样一组数据:00 FF,明显最优的选法,是只选FF,然后答案是FF^0=FF.接下来的问题就是,如何确定k。
^k这个式子,我们只需要关注k的后面8位二进制大小即可,假设k的二进制表示
为1011 0010 0101 1001 而a
最大为0000 0000 1111 1111, k^a
= 1011 0010
1010 0110,前面8位二进制是不变的,所以,只需要关注后面8位的情况即可,那么对于前面8位
肯定希望他越大越好,因为他是不受a
影响的,而后面8位就要受a
影响了,所以我们只需要
枚举一遍后面8位的情况,即0-255,所以我们用dp[i][j],i代表前i个数并且一定选第i个数,
假设当前子序列长度为k,那么j代表k的二进制表示的最后8位对应的十进制数,那么:
dp[i][j] = id_mod[j-1] + k^a[i]
id_mod[j]代表id后8位对应的十进制为j的最大值,如何求k呢?因为我们要使前面选的越多越好,
因为要保证当前的j=k%256,前面最多选k-1 = i/256*256+j-1, 而id_mod可以在每次计算完一个
dp[i]后更新.
代码:
题意:给出n个1个字节的数(1<=n<=100000),用16进制的形式给出,每个数的范围00-FF,
找出一个子序列s, 使得0^s[0]+1^s[1]+2^s[2]+…k^s[k]的和最大,输出这个最大值。
第一步:
首先很容易想到一个简单的dp方程dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+(arr[i]^j))
dp[i][j]:代表前i个数一共选了j个数能得到的最大和。但是,这样时间复杂度和空间复杂度都为1e10,
明显需要优化
如何优化呢?
从输入数据最大为FF:255可以看出要从输入数据入手,先考虑最后一个数a,即第n
个数,选还是不选?如果选,应该让他在子序列对应的位置为多少(即子序列的长度),
仔细想想,可以明确,第n个数一定要选,[因为:如果没有选最后一个数的话,假设,
我们的最终选的子序列为s[0],s[1],s[2]…s[k], 答案假设为ans, 如果我们把第n个数加进去
的话,那么最终的答案为ans+(a
^(k+1)),由于所有的数都为正数,所以这个答案一定>=不选第
n个数的答案], 那么如果选第n个数的话,假设最终子序列的长度为k的话,应该让k为多大合适呢?
k是不是越大越好呢?首先明确:k不是越大越好,。假设有这样一组数据:00 FF,明显最优的选法,是只选FF,然后答案是FF^0=FF.接下来的问题就是,如何确定k。
。。。
事实上,对于a^k这个式子,我们只需要关注k的后面8位二进制大小即可,假设k的二进制表示
为1011 0010 0101 1001 而a
最大为0000 0000 1111 1111, k^a
= 1011 0010
1010 0110,前面8位二进制是不变的,所以,只需要关注后面8位的情况即可,那么对于前面8位
肯定希望他越大越好,因为他是不受a
影响的,而后面8位就要受a
影响了,所以我们只需要
枚举一遍后面8位的情况,即0-255,所以我们用dp[i][j],i代表前i个数并且一定选第i个数,
假设当前子序列长度为k,那么j代表k的二进制表示的最后8位对应的十进制数,那么:
dp[i][j] = id_mod[j-1] + k^a[i]
id_mod[j]代表id后8位对应的十进制为j的最大值,如何求k呢?因为我们要使前面选的越多越好,
因为要保证当前的j=k%256,前面最多选k-1 = i/256*256+j-1, 而id_mod可以在每次计算完一个
dp[i]后更新.
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long Long; const int maxn = 1e5 + 10; const int maxm = 256; Long dp[maxn][maxm], id_mod[maxn]; int arr[maxn]; int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; i++) { scanf("%x", &arr[i]); } memset(id_mod, 0, sizeof(id_mod)); memset(dp, 0, sizeof(dp)); for (int i = 0; i < n; i++) { for (int j = 0; j < maxm; j++) { int x = i/maxm*maxm+j; if (x > i) x -= maxm; if (x < 0) continue; dp[i][j] = id_mod[(j-1+maxm)%maxm] + (arr[i]^x); } for (int j = 0; j < maxm; j++) { id_mod[j] = max(id_mod[j], dp[i][j]); } } Long ans = 0; for (int i = 0; i < maxm; i++) { ans = max(ans, dp[n-1][i]); } printf("%I64d\n", ans); } return 0; }
相关文章推荐
- 杭电1069--Monkey and Banana 子序列,dp
- 圆角图片
- Shiro使用和源码分析---5
- A. Vitaly and Night
- [问题排障] ssh登录,密码提示出现慢的解决方法
- lightoj1297(二分查找,或求导)
- react native image resizeMode理解
- gdb反向调试命令
- 2015.11.10 asn1学习笔记
- 笑话
- 2015.11.10 asn1学习笔记
- LabVIEW教程之显示图像的方法二控件显示图像
- 杭电2896题 AC自动机模板题
- 西普ctf解题思路——《貌似有点难》
- VC中CStatic设置文字、字体、颜色和OnCtlColor的使用
- Word 导出带目录书签的PDF文档 Office
- Struts2 在IDEA<s:datetimepicker/>的问题
- 朴素贝叶斯——UCI数据集IRIS
- [kuangbin带你飞]专题一 简单搜索H - Pots(POJ 3414)
- hdu 2222 Keywords Search