Gym 100792H Hashing (DP)

来源:互联网 发布:java spring书籍 编辑:程序博客网 时间:2024/05/12 20:49

题意:给你n个1个字节的数(16进制表示)(n<=1e5),每个数的范围00-FF, 找出一个子序列s, 使得

0^s[0]+1^s[1]+2^s[2]+…k^s[k]的和最大, 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 
个数,选还是不选?如果选,应该让他在子序列对应的位置为多少(即子序列的长度), 
仔细想想,可以明确,第n个数一定要选,[因为:如果没有选最后一个数的话,假设, 
我们的最终选的子序列为s[0],s[1],s[2]…s[k], 答案假设为ans, 如果我们把第n个数加进去 
的话,那么最终的答案为ans+(a[n]^(k+1)),由于所有的数都为正数,所以这个答案一定>=不选第 
n个数的答案], 那么如果选第n个数的话,假设最终子序列的长度为k的话,应该让k为多大合适呢? 
k是不是越大越好呢?首先明确:k不是越大越好,。假设有这样一组数据:00 FF,明显最优的选法,是只选FF,然后答案是FF^0=FF.接下来的问题就是,如何确定k。

。。。

事实上,对于a[n]^k这个式子,我们只需要关注k的后面8位二进制大小即可,假设k的二进制表示 
为1011 0010 0101 1001 而a[n]最大为0000 0000 1111 1111, k^a[n] = 1011 0010 
1010 0110,前面8位二进制是不变的,所以,只需要关注后面8位的情况即可,那么对于前面8位 
肯定希望他越大越好,因为他是不受a[n]影响的,而后面8位就要受a[n]影响了,所以我们只需要 
枚举一遍后面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<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e5+5;const int mod = 256;ll dp[maxn][mod], c[mod];int a[maxn];int main(void){    int n;    while(cin >> n)    {        for(int i = 0; i < n; i++)            scanf("%x", &a[i]);        memset(c, 0, sizeof(c));        memset(dp, 0, sizeof(dp));        for(int i = 0; i < n; i++)        {            for(int j = 0; j < mod; j++)            {                int x = i/mod*mod+j;                if(x > i) x -= mod;                if(x < 0) continue;                dp[i][j] = c[(j-1+mod)%mod]+(a[i]^x);            }            for(int j = 0; j < mod; j++)                c[j] = max(c[j], dp[i][j]);        }        ll ans = 0;        for(int i = 0; i < mod; i++)            ans = max(ans, dp[n-1][i]);        printf("%lld\n", ans);    }    return 0;}


原创粉丝点击