MT2153异或和
dp[i] 表示异或和是i的序列最后一个数字,这个数字尽可能小。
举个例子,序列 0001 0010 0100 1000 和序列 0000 1111 他们都满足单调递增序列,这个时候dp[i]=1000 , 取1000和1111最小的数。
思路:
1、对于前面i-1个数字,dp数组里面已经储存了所有结果的可能
2、对于a[i] 遍历dp数组里的所有数字
(1) dp[j]==INT_MAX 没有序列结果是j
(2) dp[j]==a[x] 存在以a[x]结尾的序列,使其异或结果是j,且a[x]是最小的
这个时候,当a[x] > a[i]的时候,a[i]不能是序列的结尾,a[i]>= a[x]就可以,更新dp[j & a[i]] = max ( dp[j & a[i]] , a[i] )
感想:
1、这道题巧妙在把所有结果都存在一个数组里,用下标表示,数组就可以存序列的最后一个值,然后得到递推公式。很巧妙。
2、dp数组用0x8fff ffff初始化不行,用0x3f3f 3f3f倒是可以,长记性了
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 520;
const int X = 1e5 + 5;
int dp[N];//dp[i] 表示异或和是i的序列最后一个数字 INT_MAX表示还不是
int arr[X];
#define MAX_NUM 0x3f3f3f3f
int main()
{
memset(dp, MAX_NUM, sizeof(dp));
int n; cin >> n;
for (int i = 1; i <= n; i++)
cin >> arr[i];
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < N; j++) {
if (dp[j] < arr[i]) {
dp[j ^ arr[i]] =min( arr[i], dp[j ^ arr[i]]);
}
}
}
int res = 0;
for (int i = 0; i < N; i++) {
res += (dp[i] != MAX_NUM);
}
cout << res << endl;
for (int i = 0; i < N; i++) {
if (dp[i] != MAX_NUM)
cout << i << " ";
}
}