【NOIP2016提高A組五校聯考4】label
阿新 • • 發佈:2018-05-21
BE sdn 表示 urn con next LG 對稱 class 個,前綴和就可以直接算出來(程序中我直接求出前10010個的值,沒有計算x)。
題目
題目
20%算法
設\(f_{i,j}\)表示第i個節點選了j這個權值的方案數。
顯然轉移方程為,\[f_{i,j}=\Pi_{v=son(i)}(\sum_{k=1}^{j-k}f_{v,k}+\sum_{k=j+k}^{m}f_{v,k})\]
40%算法
接著上面的想法,
觀察轉移方程,發現,求和部分其實是兩段連續的,那麽將\(f_{i}\)求一個前綴和。
100%算法
觀察\(f\)數組,發現其實\(f\)是對稱的,而且中間的一段是相同的,設深度為x,那麽前面就有\((x-1)k\)個不同,然後中間有一段相同,後面又有\((x-1)k\)個不同。
那麽就可以只求出前\((x-1)k+1\)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> const long long maxlongint=2147483647; const long long mo=1000000007; const long long N=105; using namespace std; long long f[N][N*N*2],_,n,m,k,next[N*2],last[N*2],to[N*2],tot,same[N],sum1[N][N*N],sum2[N][N*N]; long long pos[N]; long long max(long long x,long long y) { if(x<y) return y;else return x; } long long min(long long x,long long y) { if(x>y) return y;else return x; } long long bj(long long x,long long y) { next[++tot]=last[x]; last[x]=tot; to[tot]=y; } long long sum(int x,int y) { if(y<=10010) return sum1[x][y]; else if(y<m-pos[x]+1) { return (sum1[x][pos[x]]+same[x]*(y-pos[x])%mo)%mo; } else { return (sum1[x][pos[x]]+(m-pos[x]-pos[x])*same[x]%mo+sum2[x][(y-(m-pos[x]))])%mo; } } long long dg(long long x,long long fa) { bool q=false; for(long long i=last[x];i;i=next[i]) { long long j=to[i]; if(j!=fa) { dg(j,x); q=true; } } for(long long i=1;i<=min(10010,m);i++) f[x][i]=1; for(long long i=last[x];i;i=next[i]) { long long j=to[i]; if(j!=fa) { for(long long l=1;l<=min(10010,m);l++) { long long t=0; t=(t+(sum(j,max(0,l-k))-sum(j,0)+mo))%mo; if(l+k<=m) { t=(t+(sum(j,m)-sum(j,l+k-1)+mo))%mo; if(max(0,l-k)==l+k) t=(t-f[j][l+k]+mo)%mo; } f[x][l]=(f[x][l]*t)%mo; } } } if(10010<m) { for(int i=1;i<=10010;i++) { if(f[x][i]==f[x][i+1]) { same[x]=f[x][i]; pos[x]=i-1; break; } } } else { same[x]=f[x][m/2]; } for(int i=1;i<=min(10010,m);i++) sum1[x][i]=(sum1[x][i-1]+f[x][i])%mo; for(int i=1;i<=min(10010,m);i++) sum2[x][i]=(sum2[x][i-1]+f[x][pos[x]-i+1])%mo; } int main() { scanf("%lld",&_); while(_--) { scanf("%lld%lld%lld",&n,&m,&k); memset(f,0,sizeof(f)); memset(last,0,sizeof(last)); memset(next,0,sizeof(next)); memset(sum1,0,sizeof(sum1)); memset(sum2,0,sizeof(sum2)); memset(pos,0,sizeof(pos)); tot=0; for(long long i=1;i<=n-1;i++) { long long x,y; scanf("%lld%lld",&x,&y); bj(x,y); bj(y,x); } dg(1,0); printf("%lld\n",sum(1,m)); } }
【NOIP2016提高A組五校聯考4】label