这其实是超级大水题,难度不及一道提高组的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\n",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 }