题解:P7335 [JRKSJ R1] 异或

· · 题解

提供一种没有常数的做法。

随便实现都能跑到最优解 rk1。

Solution

考虑 DP。

因为发现每次转移都只需要上一层,所以可以把 DP 数组压成一维的,重复做 $k$ 次即可。 朴素做法是对每个 $i$ 枚举所有可能的 $j$,转移 $dp_{i}\gets\max(dp_{i},dplast_{j-1}+\operatorname{xor}_{l=j}^{i}a_l)$。 最后对 DP 数组做一遍前缀 $\max$。 --- 现在考虑数据随机带来的性质。 考虑一个点往左,哪些决策点是可能的。 从这个点往左,做一个后缀异或和,则所有可能的决策点是后缀异或和的每个后缀最大值的位置。因为非后缀最大值位置会被其右边的后缀最大值位置偏序。(DP 数组不降) 对每个 $i$ 而言这个决策点的数量期望应该是 $O(\log V)$ 的。这等价于随机序列前缀 $\max$ 的数的数量。 处理出来这个信息,每次暴力转移,跑 $k$ 次 DP,就做完了。 期望 $O(nk\log V)$。 ## Code 没有经过任何卡常。 :::info[代码] ```cpp #include<bits/stdc++.h> #define inf 0x3f3f3f3f #define infll 0x3f3f3f3f3f3f3f3fll using namespace std; int n,k; int a[3010],pre[3010]; vector<int> ts[3010]; long long dp[3010],dp_last[3010]; void solve(){ memcpy(dp_last,dp,(n+1)*(sizeof(long long))); memset(dp,0,(n+1)*(sizeof(long long))); for(int i=1;i<=n;i++) for(int x:ts[i]) dp[i]=max(dp[i],dp_last[x-1]+(pre[i]^pre[x-1])); for(int i=1;i<=n;i++) dp[i]=max(dp[i],dp[i-1]); } int main(){ cin.tie(0)->sync_with_stdio(false); cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) pre[i]=pre[i-1]^a[i]; for(int i=1;i<=n;i++){ int nowxor=0,maxxor=-1; for(int p=i;p>=1;p--){ nowxor^=a[p]; if(nowxor>maxxor) ts[i].push_back(p),maxxor=nowxor; } } while(k--) solve(); cout<<dp[n]<<"\n"; # ifdef TakanashiHoshino cerr<<"\nUsed time: "<<clock()*1.0/CLOCKS_PER_SEC<<"s.\n"; # endif return 0; } ``` :::