Chino with Train to the Rabbit Town
题目链接:https://ac.nowcoder.com/acm/contest/553/G
感谢大佬博客的指点:https://www.cnblogs.com/FrankChen831X/p/10666916.html
题意
给定n,k,(1<=n<=5e5)然后给出n个数ai(1<=ai<=1e5),问按顺序从1…n分组,最多能有多少个组的异或和为k。
输入描述:第一行是两个数n, k,接下来一行是n个数ai
输出描述:题目中要求的答案
示例:
输入:
3 1
1 2 3
输出:
2
思路
首先我们需要知道 a ^ b ^ b = a, 若有 a1 ^ a2 ^ a3 ^ a4 ^ a5 ^ k = a1 ^ a2 ^ a3,则有 a4 ^ a5 = k。
DP思路,我们可以用 DP[ i ] 表示到第 i 个人的时候最多有多少组的异或和为k,下面考虑状态转移方程,DP[ i ] 的取值有两种情况。第一种:当前 ai 无法与 ai 的前面若干个意愿值异或和为k,此时DP[ i ]=DP[ i -1 ]。第二种:当前 ai 可以与ai前若干个意愿值异或和为k,即存在 j <i , a(j+1) ^ a(j+2) ^ …^ a(i) =k,DP[ i ] =max(DP[ i - 1 ] ,DP[ j ] + 1 )。如何知道是否存在这个 j 呢?我们可以用sum记录ai的异或前缀和,然后设置一个pre数组记录各sum值对应的最后一个元素下标,这样pre[ sum^k ] 即为 j 。若不存在,pre数组为默认值-1,下面看代码。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MAXN 500005
int DP[MAXN],sum;
int pre[MAXN];
int main()
{
std::ios::sync_with_stdio(false);
int n,k;
cin>>n>>k;
memset(pre,-1,sizeof(pre));
pre[0]=0;
for(int i=1;i<=n;++i){
int a;
cin>>a;
sum^=a;
if(pre[sum^k]!=-1){
DP[i]=max(DP[i-1],DP[pre[sum^k]]+1);
}
else DP[i]=DP[i-1];
pre[sum]=i;
}
cout<<DP[n]<<endl;
}