02 hdu 6121
题意
给定一棵 k 叉树,求其所有子树大小的异或和。
参考
http://blog.csdn.net/wubaizhe/article/details/77248527 ——WuBaizhe
想法
记当前的
根的所有孩子,最多只有一个不是满
左右两边都是满
k
叉树,高度分别为
递归处理即可。
注意点
k == 1时,退化成一条链,即求 1 ^ 2 ^ 3 ^ ... ^n,可打表找规律。
Code
#include <bits/stdc++.h>
#define maxn 110
typedef long long LL;
LL sz[maxn], x[maxn], n, k;
LL query(LL n, LL dep) {
// printf("%lld %lld\n", n, dep);
if (dep == 2) return n ^ ((n - 1 & 1) ? 1 : 0);
LL mod = pow(k, dep - 2);
LL ful1 = (n - sz[dep - 1]) / mod;
LL ful2 = k - ful1, ret = n ^ ((ful1 & 1) ? x[dep - 1] : 0);
if ((n - sz[dep - 1]) % mod) {
--ful2;
ret ^= ((ful2 & 1) ? x[dep - 2] : 0) ^ query(n - 1 - ful1 * sz[dep - 1] - ful2 * sz[dep - 2], dep - 1);
}
else ret ^= ((ful2 & 1) ? x[dep - 2] : 0);
return ret;
}
void work() {
scanf("%lld%lld", &n, &k);
if (k == 1) {
LL xx = n % 4;
LL ans;
switch (xx) {
case 0: ans = n; break;
case 1: ans = 1; break;
case 2: ans = n + 1; break;
case 3: ans = 0;
}
printf("%lld\n", ans);
return;
}
LL cnt = 1, cur = n, h = 1;
sz[1] = 1, x[1] = 1;
while (true) {
cur -= cnt;
cnt *= k;
sz[h + 1] = sz[h] * k + 1;
x[h + 1] = ((k & 1) ? x[h] : 0) ^ sz[h + 1];
++h;
if (cur < cnt) break;
}
printf("%lld\n", query(n, h));
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}
05 hdu 6124
题意
给定
a
,要求
思路
考虑从 a 开始往下模,最多模到一半的位置,之后得到的答案必为前面的子集。
注意
分奇偶讨论。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
void work() {
int n;
scanf("%d", &n);
int ans = 0;
if (n & 1) ans = n - (n + 1) / 2 + 1 + 1;
else ans = n - n / 2 + 1;
printf("%d\n", ans);
}
int main() {
// freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}
08 hdu 6127
题意
给定平面上
参考
http://blog.csdn.net/trancyqing/article/details/77234510
官方题解
对于一条直线,线段权值和实际上就等于其两边点权和的乘积,所以把所有点按极角排个序,然后扫一圈就好了。
Code
#include <bits/stdc++.h>
#define eps 1e-6
#define PI acos(-1.0)
#define maxn 50010
typedef long long LL;
using namespace std;
struct node {
int x, y;
double a;
LL v;
bool operator < (const node nd) const {
return a < nd.a;
}
}p[maxn];
void work() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d%d%lld", &p[i].x, &p[i].y, &p[i].v);
if (p[i].x == 0) p[i].a = PI / 2;
else p[i].a = atan((double)p[i].y / p[i].x);
}
sort(p, p + n);
// for (int i = 0; i < n; ++i) printf("%d %d %.3f\n", p[i].x, p[i].y, p[i].a);
LL lsum = 0, rsum = 0;
for (int i = 0; i < n; ++i) {
if (p[i].x >= 0) rsum += p[i].v;
else lsum += p[i].v;
}
LL ans = rsum * lsum;
for (int i = 0; i < n; ++i) {
if (p[i].x >= 0) {
rsum -= p[i].v;
lsum += p[i].v;
}
else {
lsum -= p[i].v;
rsum += p[i].v;
}
ans = max(ans, rsum * lsum);
}
printf("%lld\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}
10 hdu 6129
题意
对给定的数组 a[] 求 m 次前缀异或,输出最终的数组。
参考
http://blog.csdn.net/mengxiang000000/article/details/77200451
想法
找规律。也要找对路子。
考虑第一个元素对后面第
i
行第
第
i
行第
注意点
乍一看是
n2
的,事实上 第一个元素对第
j
列的贡献次数 就相当于 第二个元素对第
至于判断组合数的奇偶:Lucas定理
对于
反思
一开始找规律找歪了,每四次前四个循环,每八次前八个循环,每十六次前十六个循环,然而按照这规律写还是 n2 的,T到最后。
Code
#include <bits/stdc++.h>
#define maxn 200010
using namespace std;
int n,m, a[maxn], b[maxn], ans[maxn];
void work() {
scanf("%d %d", &n, &m);
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
int mod = 1;
while (mod < n) mod <<= 1;
m %= mod;
for (int i = 1; i <= n; ++i) {
int deno = m + i - 2, nomi = i - 1;
if ((deno & nomi) == nomi) {
for (int j = 1; j <= n - i + 1; ++j) ans[i + j - 1] ^= a[j];
}
}
printf("%d", ans[1]);
for (int i = 2; i <= n; ++i) {
printf(" %d", ans[i]);
}
printf("\n");
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}
10 hdu 6130
题意
序列一:
1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1,2,2,1,...
序列二:
1,22,11,2,1,22,1,22,11,2,11,22,1,...
将序列一分组得到序列二,将序列二中每组的元素个数写下来得到序列一。
思路
直接模拟即可,用序列一生成序列二。
Code
#include <bits/stdc++.h>
#include <vector>
#define maxn 10000000
int a[maxn + 10];
using namespace std;
vector<int> G;
typedef long long LL;
void init() {
int tot = 2, i = 2, j = 2;
a[0] = 1, a[1] = 2, a[2] = 2;
while (i >= j) {
int temp = a[j];
if (temp == 1) {
a[i + 1] = 3 - a[i];
i += 1;
}
else {
a[i + 1] = a[i + 2] = 3 - a[i];
i += 2;
}
j += 1;
if (i >= 1e7) break;
}
}
void work() {
int n;
scanf("%d", &n);
printf("%d\n", a[n-1]);
}
int main() {
// freopen("in.txt", "r", stdin);
init();
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}