luogu P3565 [POI2014]HOT-Hotels(ggg)
阿新 • • 發佈:2018-12-02
無腦暴力+O2=AC
題目要統計距離兩兩相等的三個點的組數,這三個點之間顯然有一個點,並且這三個點到這個點的距離都相同.所以列舉中間這個點作為根,然後bfs整棵樹,對於每一層,把以根的某個兒子的子樹中在這一層點的數量統計出來,那麼這樣三元組的數量就是在這些點裡面選3個點,並且分別來自不同子樹的方案,\(f_{i,0/1/2/3}\)即可
詳見程式碼
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long long #define il inline #define re register using namespace std; const int N=5000+10; il int rd() { int x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } LL ans,f[N][4]; int to[N<<1],nt[N<<1],hd[N],dg[N],tot=1,a[N]; bool v[N]; il void add(int x,int y) { ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot,++dg[x]; ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot,++dg[y]; } int n,m; int main() { n=rd(); for(int i=1;i<n;++i) add(rd(),rd()); for(int i=0;i<=n;++i) f[i][0]=1; queue<int> id[2],q[2]; for(int i=1;i<=n;++i) { memset(v,0,sizeof(v)); v[i]=1; while(!id[0].empty()) id[0].pop(); while(!id[1].empty()) id[1].pop(); while(!q[0].empty()) q[0].pop(); while(!q[1].empty()) q[1].pop(); m=dg[i]; int nw=1,la=0; for(int j=hd[i],k=1;j;j=nt[j],++k) id[0].push(k),q[0].push(to[j]); while(!q[la].empty()) { memset(a,0,4*(m+1)); while(!q[la].empty()) { int k=id[la].front(),x=q[la].front(); id[la].pop(),q[la].pop(); ++a[k],v[x]=true; for(int j=hd[x];j;j=nt[j]) { int y=to[j]; if(!v[y]) id[nw].push(k),q[nw].push(y); } } for(int j=1;j<=m;++j) { for(int k=1;k<=3;++k) f[j][k]=f[j-1][k]+f[j-1][k-1]*a[j]; } ans+=f[m][3]; swap(nw,la); } } printf("%lld\n",ans); return 0; }
正解是長鏈剖分
咕咕咕