HDU多校第九场

1001 Tree

题意,给一棵树,根节点为1,父节点可以去任意儿子节点,可以添加一条边使得u可以到达v,问添加这样一条边后所有的节点可以去向的节点总和的最大值

思路:连接叶子结点和根节点,遍历一遍求得最大值

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define INF 0x3f3f3f3f
#define pi 3.141592654
typedef long long ll;
const int N = 5e5+5;
int tot,ma,id,n;
int nex[N*2],head[N*2],ver[N*2];
ll ans,res;
void add(int u, int v){
    ver[++ tot] = v;
    nex[tot] = head[u];
    head[u] = tot;
}
int num[N],d[N];
void dfs(int pos){
    num[pos] = 1;
    for(int i=head[pos] ; i ; i = nex[i]){
        d[ver[i]] = d[pos] + 1;
        dfs(ver[i]);
        num[pos] += num[ver[i]];
    }
    ans += ll(num[pos]);
}
void dfs2(int pos,ll sum){///不同的叶子结点是有区别的
    res = max(res,ans + 1ll * n * (d[pos]+1) - sum);
    for(int i = head[pos]; i ; i = nex[i])
        dfs2(ver[i],sum + num[ver[i]]);
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        int x;scanf("%d",&n);
        for(int i=1;i<=n;i++)   head[i]=0;
        d[1] = 0;tot=0;
        for(int i = 2; i<= n ;i++){
            scanf("%d",&x);
            add(x,i);
        }
        ans = 0;res=0;
        dfs(1);
        dfs2(1,1ll*num[1]);
        printf("%lld\n",res);
    }
    return 0;
}

1003 Slime and Stones

题意:给两堆石子,一堆为a,一堆为b,两个人依次取石子,可以从任意一堆石子取任意个,或者从两堆石子取差值不超过k的数量的石子。给出这样的a,b,k。问是否为先手必胜

思路:

威佐夫博弈扩展:
betty:设a、b是正无理数且 1/a +1/b =1。记P={ [na] | n为任意的正整数},
Q={ [nb] | n 为任意的正整数},([x]指的是取x的整数部分)则P与Q是N+的一个划分,
即P∩Q=Ø且P∪Q=N+(正整数集)。
k = 0时,(威佐夫博弈)
根据betty定理,对于1/A+1/B=1,必有
Ua={trunc(An),n为正整数}///trunc为去除小数部分
Ub={trunc(B
n),n为正整数}
Ua与Ub的并集构成正整数集且Ua于Ub不相交
所以设某个必败态的第一项为trunc(An),第二项为trunc(An+n)=trunc((A+1)n)
则1/A+1/(A+1)=1
求得 A=(sqrt(5)+1)/2; B =(sqrt(5)+ 3)/2
k > 1(扩展)
第一个必败态 trunc(A),trunc(A + k +1 )
第二个必败态 trunc(2
A),trunc(2A + 2(k+1))
设第n个必败态的第一项为 trunc(An),第二项为trunc(nA + n*(k+1))
则1/A + 1/(A+k+1) = 1
求得A = (1 - k + sqrt(k^2+2k+5))/2, B = A + k+1 = (3 + k + sqrt(k^2+2k+5))/2

代码:

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define INF 0x3f3f3f3f
#define pi 3.141592654
typedef long long ll;
const int N = 5e5+5;
int main(){
    int t;scanf("%d",&t);
    ll k,a,b;
    while(t--){
        scanf("%lld %lld %lld",&a,&b,&k);
        if( a > b){ll tem = a; a = b ; b = tem;}
        ll n = (b - a) / (k+1);
        double A = (1 - k + sqrt(k*k+2*k+5))/2;
        double B = A + k + 1;
        if(ll(A*n) == a && ll(B*n) == b)
            printf("0\n");
        else
            printf("1\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值