洛谷 P3237 [HNOI2014]米特運輸
阿新 • • 發佈:2018-03-23
... bool ati opera 行修改 per 數據 好的 tdi
這其實是超級大水題,難度不及一道提高組的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 #defineeps 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 }
洛谷 P3237 [HNOI2014]米特運輸