8.18 18级杭电多校第九场

比赛过程

  手速场,签到题和其他题难度差距有点大,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两堆石头两个人玩游戏轮流取,游戏规则如下:

  1. 选一堆石头取任意k个
  2. 在两堆石头中分别取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 +1k

  1. 在|a-b|小于k+1时必胜;
  2. 当|a-b|==(k+1)的倍数,且 ∣ a − b ∣ ( k + 1 ) × α = a \frac{|a-b|}{(k+1)} × α=a (k+1)ab×α=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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值