比赛过程
手速场,签到题和其他题难度差距有点大,1003看了半天才发现可以套类威佐夫博弈的代码,这种东西还是见多识广才能做的快。
1001(654/2899) Tree
tag:树上dp
题意
给一棵树,父亲节点可以到达儿子节点,现在要你连接任意两个不连通的节点,问最多有多少对(x, y),表示从x可以到达y。
思路
最优解一定是某个叶子结点连向根节点,那么这条路径上的点给予的权值就会变成n,直接dfs一遍求出所有答案取最大值即可。
int _, n, fa, cnt[N];
int head[N], ver[M], nex[M], tot;
ll sum, ans;
void add(int x, int y) {
ver[++tot] = y, nex[tot] = head[x], head[x] = tot;
}
void dfs1(int x) {
cnt[x] = 1;
for(int i = head[x]; i; i = nex[i]) {
int y = ver[i];
dfs1(y);
cnt[x] += cnt[y];
}
sum += cnt[x];
}
void dfs2(int x, ll tmp) {
ans = max(ans, tmp);
for(int i = head[x]; i; i = nex[i]) {
int y = ver[i];
dfs2(y, tmp + (n - cnt[y]));
}
}
int main() {
for(scanf("%d", &_); _--; ) {
ans = sum = tot = 0;
scanf("%d", &n);
rep(i, 1, n) head[i] = 0;
rep(i, 2, n) {
scanf("%d", &fa);
add(fa, i);
}
dfs1(1); dfs2(1, sum);
printf("%lld\n", ans);
}
return 0;
}
1003(242/1778) Slime and Stones
tag:威佐夫博弈、BEATTY定理
题意
给a,b两堆石头两个人玩游戏轮流取,游戏规则如下:
- 选一堆石头取任意k个
- 在两堆石头中分别取x个和y个,但是x和y之差不得大于k。
先取完石头的人获胜,问你先手能否获胜。
思路
当k=0时,这个题会退化成威佐夫博弈。威佐夫博弈的必胜态差值为
n
×
(
5
+
2
)
2
\frac{n×(\sqrt5 + 2)}{2}
2n×(5+2)。
根据BEATTY函数,若a,b两堆数,a和b不相交且a,b是正无理数,则
1
a
+
1
b
=
1
\frac{1}{a} + \frac{1}{b} = 1
a1+b1=1,在威佐夫博弈中,根据BEATTY函数,
1
α
+
1
(
α
+
1
)
=
1
\frac1α+\frac{1}{(α+1)}=1
α1+(α+1)1=1,同样的我们可以得到:
1
α
+
1
+
1
α
+
k
+
1
=
1
\frac{1}{α+1} + \frac{1}{α+k+1} = 1
α+11+α+k+11=1,因此
α
=
k
2
+
2
k
+
5
+
1
−
k
2
α= \frac{\sqrt{k^2 + 2k + 5} + 1 - k}{2}
α=2k2+2k+5+1−k。
- 在|a-b|小于k+1时必胜;
- 当|a-b|==(k+1)的倍数,且 ∣ a − b ∣ ( k + 1 ) × α = a \frac{|a-b|}{(k+1)} × α=a (k+1)∣a−b∣×α=a 时,先手必败;
ll _, a,b,k;
int main(){
for(cin >> _; _--; ) {
scanf("%lld%lld%lld", &a, &b, &k);
if(a > b) swap(a,b);
ll cha = b - a;
db alpha = sqrt(k*k + 2*k + 5) * 1.0 + 1 - k;
if(cha % (k+1) || ll(cha / (k+1) / 2.0 * alpha) != a) {
puts("1");
} else puts("0");
}
return 0;
}
// dls题解算范围
int main(){
for(cin >> _; _--; ) {
scanf("%lld%lld%lld", &a, &b, &k);
if(a > b) swap(a,b);
ll cha = b - a;
cha /= (k + 1);
db tmp = sqrt(k*k + 2*k + 5);
// 公式求左右奇异局势
db x = (1 - k + tmp) / 2.0, y=(3 + k + tmp) / 2.0;
if((ll)(x * cha) != a || (ll)(y * cha) != b) puts("1");
else puts("0");
}
return 0;
}