poj 3764 The xor-longest Path
题意:给定一棵树,问你最长的异或路径。
思路:想到 LCA 就差不多了,我们记录根到节点i路径的 ⊗ 值 ans[i] 。
这样对于 u−>v 路径的异或值为 ans[u]⊗ans[v] 。
相当于给定 n−1 个数,求解 max (两两异或的最大值, 单个的最大值)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
struct Edge {
int from, to, val, next;
};
Edge edge[MAXN * 2];
int head[MAXN], edgenum;
void addEdge(int u, int v, int w) {
Edge E = {u, v, w, head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
int Next[31 * MAXN][2], word[31 * MAXN], L, root;
int f[40];
int newnode() {
Next[L][0] = Next[L][1] = -1;
word[L++] = 0;
return L - 1;
}
void init() { L = 0; root = newnode(); }
void Insert(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(Next[u][v] == -1) {
Next[u][v] = newnode();
}
u = Next[u][v];
word[u]++;
}
}
int Query(int val) {
int ans = 0; int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(v == 0) {
if(Next[u][1] != -1 && word[Next[u][1]]) {
ans ^= f[i]; u = Next[u][1];
}
else {
u = Next[u][0];
}
}
else {
if(Next[u][0] != -1 && word[Next[u][0]]) {
ans ^= f[i]; u = Next[u][0];
}
else {
u = Next[u][1];
}
}
}
return ans;
}
int val[MAXN];
void DFS(int u, int fa) {
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(v == fa) continue;
val[v] = val[u] ^ edge[i].val;
DFS(v, u);
}
}
int main()
{
f[0] = 1;
for(int i = 1; i <= 30; i++) {
f[i] = f[i - 1] * 2;
}
int n;
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) head[i] = -1, val[i] = 0;
edgenum = 0;
for(int i = 1; i <= n - 1; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
u++; v++;
addEdge(u, v, w); addEdge(v, u, w);
}
DFS(1, -1); init(); int ans = 0;
for(int i = 2; i <= n; i++) {
Insert(val[i]);
ans = max(ans, val[i]);
}
for(int i = 2; i <= n; i++) {
ans = max(Query(val[i]), ans);
}
printf("%d\n", ans);
}
return 0;
}
lightoj 1269 - Consecutive Sum
题意:给你连续子序列的最大异或值和最小异或值。
维护前缀异或和即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 5e4 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
struct Edge {
int from, to, val, next;
};
Edge edge[MAXN * 2];
int head[MAXN], edgenum;
void addEdge(int u, int v, int w) {
Edge E = {u, v, w, head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
int Next[31 * MAXN][2], word[31 * MAXN], L, root;
int f[40];
int newnode() {
Next[L][0] = Next[L][1] = -1;
word[L++] = 0;
return L - 1;
}
void init() { L = 0; root = newnode(); }
void Insert(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(Next[u][v] == -1) {
Next[u][v] = newnode();
}
u = Next[u][v];
word[u]++;
}
}
int Query_Max(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(v == 0) {
if(Next[u][1] != -1 && word[Next[u][1]]) {
val ^= f[i]; u = Next[u][1];
}
else {
u = Next[u][0];
}
}
else {
if(Next[u][0] != -1 && word[Next[u][0]]) {
u = Next[u][0];
}
else {
val ^= f[i]; u = Next[u][1];
}
}
}
return val;
}
int Query_Min(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(v == 1) {
if(Next[u][1] != -1 && word[Next[u][1]]) {
val ^= f[i]; u = Next[u][1];
}
else {
u = Next[u][0];
}
}
else {
if(Next[u][0] != -1 && word[Next[u][0]]) {
u = Next[u][0];
}
else {
val ^= f[i]; u = Next[u][1];
}
}
}
return val;
}
int main()
{
f[0] = 1;
for(int i = 1; i <= 30; i++) {
f[i] = f[i - 1] * 2;
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int n; scanf("%d", &n);
init(); int ans1 = 0, ans2 = (int)((1LL << 31) - 1);
int sum = 0;
for(int i = 1; i <= n; i++) {
int v; scanf("%d", &v); sum ^= v;
if(i > 1) {
ans1 = max(Query_Max(sum), ans1);
ans2 = min(Query_Min(sum), ans2);
}
Insert(sum);
ans1 = max(sum, ans1);
ans2 = min(sum, ans2);
}
printf("Case %d: %d %d\n", kcase++, ans1, ans2);
}
return 0;
}
hdoj 5715 XOR 游戏
有毒。。。
字典树节点 Next[u][0]=−1 一直WA,找了一小时bug,发现改成 Next[u][0]=0 莫名AC?
思路:考虑二分答案,这样就变成了判定性问题。
对于当前的答案 o ,我们只要证明 n 个数分 m 段后所有段最小值大于 o 即可。
即有 dp[i][j] 前 i 个数分 j 段对于答案 o 是否合法。
dp[i][j]=(sum[k]⊗sum[i]>=o)(i−L<=k<i && dp[k][j−1]==true)
每次在字典树上插入合法的 dp[k][j−1] ,然后就是判断在所有合法的 dp[k][j−1] 里面是否存在一个 k 使得 sum[k]⊗sum[i]>=o 且 i−L<=k<i 。
那样就是求解异或 sum[i] 后的最大值了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e4 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
int f[31];
struct Trie {
int Next[31 * MAXN][2], word[31 * MAXN], L, root;
int newnode() {
Next[L][0] = Next[L][1] = 0; word[L++] = 0;
return L - 1;
}
void init() { L = 0; root = newnode(); }
void Insert(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(Next[u][v] == 0) {
Next[u][v] = newnode();
}
u = Next[u][v];
word[u]++;
}
}
void Delete(int val) {
int u = root;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
u = Next[u][v];
word[u]--;
}
}
int Query(int val) {
int u = root, ans = 0;
for(int i = 30; i >= 0; i--) {
int v = (val & f[i]) ? 1 : 0;
if(Next[u][v ^ 1] != 0 && word[Next[u][v ^ 1]]) {
ans ^= f[i]; u = Next[u][v ^ 1];
}
else {
u = Next[u][v];
}
}
return ans;
}
}; Trie trie[11];
bool dp[MAXN][11];
int sum[MAXN];
int N, M, L;
bool judge(int o) {
for(int i = 0; i <= M; i++) {
trie[i].init();
}
for(int i = 0; i <= N; i++) {
for(int j = 0; j <= M; j++) {
dp[i][j] = false;
}
}
trie[0].Insert(sum[0]); dp[0][0] = true;
for(int i = 1; i <= N; i++) {
for(int j = M; j >= 1; j--) {
if(i - L > 0) {
if(dp[i - L - 1][j - 1]) {
trie[j - 1].Delete(sum[i - L - 1]);
}
}
if(trie[j - 1].Query(sum[i]) >= o) {
dp[i][j] = true;
trie[j].Insert(sum[i]);
}
}
}
return dp[N][M];
}
int main()
{
f[0] = 1;
for(int i = 1; i <= 30; i++) {
f[i] = f[i - 1] * 2;
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &N, &M, &L);
sum[0] = 0;
for(int i = 1; i <= N; i++) {
int v; scanf("%d", &v);
sum[i] = sum[i - 1] ^ v;
}
int l = 0, r = (1 << 30) - 1;
int ans = 0;
while(r >= l) {
int mid = l + r >> 1;
if(judge(mid)) {
ans = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
printf("Case #%d:\n%d\n", kcase++, ans);
}
return 0;
}
几道水题
lightoj 1114 - Easily Readable
lightoj 1129 - Consistency Checker
lightoj 1224 - DNA Prefix
这道题有点意思吧,n个串中选出任意个。问max(串数目 * 公共前缀长度)
就相当于把串扫一遍,统计最小覆盖。中间要加个特判剪枝。