题解 ARC156D 【Xor Sum 5】
给个简单做法,不用 Lucas 定理,不用生成函数!
考虑到异或满足相同抵消为
不难发现对于一个序列
于是我们只需要对回文的
此时,如果
然而如果
于是一个很自然的想法就是把整体加的这一项记下来。发现这样就可以完成所有计算:
- 对于
K 是奇数的情况,可以直接枚举中间的项是什么,然后把它加到整体加的项里面,即可转化为K 是偶数的情况。 - 对于
K 是偶数的情况,最后一位的值只和整体加的量,以及折半以后可能的序列个数有关。前者已经被记录,后者只和N\bmod 2 有关,于是可以计算出最后一位;剩下的位就是折半后整体加当前的整体加的量的二分之一下取整的值。(这一部分可以结合下面的转移式理解)
于是我们就得到了最终的做法:
设
对于偶数
对于奇数
边界状态:
目标状态为
归纳易证第二维的最大值就是序列
#include <bits/stdc++.h>
using namespace std;
int n, a[1005];
long long k, dp[77][1005];
bool vis[77][1005];
inline void Read() {
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> a[i];
}
inline long long Dfs(int dep, int pls) {
if (vis[dep][pls]) return dp[dep][pls];
if ((k >> dep) == 1) {
vis[dep][pls] = 1;
for (int i = 1;i <= n;i++) dp[dep][pls] ^= (a[i] + pls);
return dp[dep][pls];
}
vis[dep][pls] = 1;
if (!((k >> dep) & 1)) return dp[dep][pls] = (Dfs(dep + 1, pls >> 1) << 1) | ((pls & 1) && (n & 1));
else {
dp[dep][pls] = 0;
for (int i = 1;i <= n;i++) dp[dep][pls] ^= (Dfs(dep + 1, (pls + a[i]) >> 1) << 1) | (((pls + a[i]) & 1) && (n & 1));
return dp[dep][pls];
}
}
int main() {
Read();
cout << Dfs(0, 0) << endl;
return 0;
}