【题解】[COCI2016-2017#1] Mag

solution:
先抛出结论:
-
若不存在魔力值为 1 1 1 的节点,则魔力值最小的路径即为魔力值最小的节点。
-
若存在魔力值为 1 1 1 的节点,那么要么全部由 1 1 1构成,要么由 1 1 1个 2 2 2和若干 1 1 1构成。
证明:
假设有一条最长的魔力值路径,可分为三种情况:
3. 没有为1的路径,那么显然不如
1
t
\frac{1}{t}
t1,其中
t
t
t是最小值
4. 有1段全为1的路径,假设长度为
t
t
t,其余部分乘积为
q
q
q,个数为
s
s
s,有不等式:
1
t
<
q
t
+
s
\frac{1}{t}<\frac{q}{t+s}
t1<t+sq
因为
q
>
s
,
t
>
=
1
q>s,t>=1
q>s,t>=1,所以
t
q
>
=
t
+
s
tq>=t+s
tq>=t+s,显然得证
5. 有两段以上全为1的路径,考虑连接这两个部分的路径,设乘积为
q
q
q,假如
q
>
2
q>2
q>2,其实不如选两段中较大的全为1的部分,因为分母的增量比原分母小,而分子的增量大于原分子,所以会更大,不会成为答案。当且仅当中间乘积为2即只有一个2时可能成为答案。
得证。
后记:
然后就没什么好说的了吧。。。
这道题告诉我们什么呢,分子是乘积,而分母的增量只有1,所以分子选大于1的数总是亏的。
但是这道题的结论有点违背常理可能是我太菜了,总之如果你的数学功底不好,光凭直觉还是不好想的。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int head[N*2],nxt[N*2],to[N*2],cnt;
int n,p,q,val[N],f[N],g[N];
void add(int x,int y) {
to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
}
int gcd(int x,int y) {
if(y==0) return x;
return gcd(y,x%y);
}
void write(int x,int y) {
int t=gcd(x,y);
x/=t,y/=t;
printf("%lld/%lld",x,y);
}
void change(int x,int y) {
if(p==0&&q==0) p=x,q=y;
else if(1.0*x/y<1.0*p/q) p=x,q=y;
}
void dfs(int x,int fath) {
f[x]=g[x]=0;
if(val[x]==1) f[x]=1;
if(val[x]==2) g[x]=1;
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(y==fath) continue;
dfs(y,x);
if(val[x]==1) change(1,f[y]+f[x]),change(2,g[y]+f[x]),change(2,g[x]+f[y]),f[x]=max(f[x],f[y]+1),g[x]=max(g[x],g[y]+1);
else if(val[x]==2) change(2,g[x]+f[y]),g[x]=max(g[x],f[y]+1);
}
}
signed main() {
n=read();
for(int i=1;i<n;i++) {
int x=read(),y=read();
add(x,y); add(y,x);
}
for(int i=1;i<=n;i++) val[i]=read();
int flag=0,Min=0x3f3f3f3f;
for(int i=1;i<=n;i++)
if(val[i]==1) flag=1;
else Min=min(Min,val[i]);
if(!flag) {
printf("%lld/1",Min);
return 0;
}
dfs(1,0);
write(p,q);
}
顺便说一下:最近做了做 G S S GSS GSS系列,发现数据结构的题还是看功底,知道了思路就极其简单。

浙公网安备 33010602011771号