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(Bn),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(2A),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;
}