洛谷 P3237 [HNOI2014]米特运输

这其实是超级大水题,难度不及一道提高组的dp,如果读懂了题面...

好吧我读懂了题面,然而并不知道1号节点是否一定要装满...

(根据做题的情况来看1号也是要装满的,尽管不进行能量收集)

然而为什么我还是不会做呢。。。。

稍微观察一下就可以发现:

根节点容量确定后,整棵树容量都可以确定。

因此如果要保证树上某一节点的容量不进行修改,那么根节点必须为某一确定容量

记ncn[i]为i节点的子节点个数,那么对于原来容量为a[i]的节点i,如果不能修改,则要求根节点容量为

a[i]*(i到根节点的路径上所有点的ncn值的乘积(不含i,含根节点))。

那么求出所有节点保证它们不修改要求的根节点容量,找出出现次数最多的那个,其出现次数为ans,则答案为n-ans.

稍微看一下就可以发现这样子肯定是爆longlong了,都不知道爆到哪里去了。。。。然后我就不会了。。

有一些很好的方法:

1.可以发现最终只会计算出n个答案(尽管很大),并不怎么会冲突,因此乘法可以取模(不放心可以多算几份取不同模的)

2.同上,可以用log(n)代替n,而计算乘法时,log(ab)=log(a)+log(b),使要记录的数据值大大缩小

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<map>
 5 #define eps 1e-7
 6 using namespace std;
 7 struct E
 8 {
 9     int to,nxt;
10 }e[1000010];
11 int f1[500100],ne,n,a[500100],ncn[500100],ans;
12 double dis[500100];
13 void dfs(int u,int fa)
14 {
15     for(int k=f1[u];k;k=e[k].nxt)
16         if(e[k].to!=fa)
17         {
18             dis[e[k].to]=dis[u]+log(ncn[u]);
19             dfs(e[k].to,u);
20         }
21 }
22 struct Cmp
23 {
24     bool operator()(double a,double b)
25     {
26         if(fabs(a-b)<eps)    return 0;
27         else    return a<b;
28     }
29 };
30 map<double,int,Cmp> ma;
31 int main()
32 {
33     int i,x,y;
34     scanf("%d",&n);
35     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
36     for(i=1;i<n;i++)
37     {
38         scanf("%d%d",&x,&y);
39         e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
40         e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
41         ncn[x]++;ncn[y]++;
42     }
43     for(i=2;i<=n;i++)    ncn[i]--;
44     dfs(1,0);
45     for(i=1;i<=n;i++)    dis[i]+=log(a[i]),ma[dis[i]]++;
46     //for(i=1;i<=n;i++)  printf("%lf
",dis[i]);
47     for(map<double,int,Cmp>::iterator it=ma.begin();it!=ma.end();++it)    ans=max(ans,it->second);
48     printf("%d",n-ans);
49     return 0;
50 }
原文地址:https://www.cnblogs.com/hehe54321/p/8629738.html