Description
给出一颗根为1的有根树,每个节点有两个值
ax,bx
,
bx
表示当前节点的攻击力,如果点y在点x的子树中,切
by<bx
,则x会向y发起
ax
次进攻,现在已知每个点的a值,每个点的b值在0~m之间,求全局恰好发生i次进攻的方案数(
0<=i<=K
)。
n<15,K<=20
solution
显然发现m是没有什么用的,只要记录b的相对大小,最后乘上组合数即可,
试着把每个点按b的大小依次插入,
设DP
fi,j,k
表示b有i个不同的数,发生了j次进攻,k为压缩的状态,表示哪些点选了,
每次枚举新增哪些点,转移显然,
复杂度:
O(nm3n)
试着想优化
先把每个点按照它的dfs序进行重编号,
我原来的方法是每次枚举一堆点同时转移,那么这很显然不是最优的,我们可以把这一堆点一步一步的转移过来,也就是每次只枚举一个点,
但这显然有问题,因为我会误把本来b值与我相同的点视为补我小的,
那么,只要我们消除上面的影响即可,
按深度从小到大枚举(dfs序),每次枚举选这个点,
这样,b值与我相同的点都在我的上方,也就不会对我造成影响,
(当然,在此之前别忘了从i-1转移过来)
这个很难理解,读者可以自己想一下或看下面的标称
复杂度: O(n2m2n)
Code
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
using namespace std;
const int N=22,M=32770,mo=1e9+7;
typedef long long LL;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,m1;
int B[2*N][2],A[N],B0;
struct qqww
{
int si,zx;
}a[N];
int b[N],b0;
int zx[N],er[N];
int f[N][N][M],ans;
int ej[16],c[N][M];
LL jcn[N];
LL ksm(LL q,LL w)
{
LL ans=1;
while(w)
{
if(w&1)ans=ans*q%mo;
q=q*q%mo;
w>>=1;
}
return ans;
}
LL JC(LL l,int r)
{
LL ans=1;
for(;l<=r;l++)ans=ans*l%mo;
return ans;
}
LL C(int m,int n){return JC(m-n+1,m)*jcn[n]%mo;}
void link(int q,int w)
{
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q;
}
int dfs(int q,int fa)
{
a[q].si=1;a[q].zx=++b0;zx[b0]=q;
efo(i,q)if(B[i][1]!=fa)a[q].si+=dfs(B[i][1],q);
return a[q].si;
}
int main()
{
freopen("escape.in","r",stdin);
freopen("escape.out","w",stdout);
int q,w;
er[1]=1;fo(i,2,16)er[i]=er[i-1]<<1;
read(n),read(m1),read(m);m1++;
fo(i,1,n)read(b[i]);
fo(i,2,n)link(i,read(q));
dfs(1,0);
fo(i,1,er[n+1]-1)
{
fo(j,1,n)ej[j]=ej[j-1]+((er[j]&i)!=0);
fo(j,1,n)c[j][i]=(ej[j+a[zx[j]].si-1]-ej[j])*b[zx[j]];
}
f[0][0][0]=1;
fo(I,1,min(n,m1))
fo(k,1,n)
fo(i,0,m)
for(int j=er[k];j<er[n+1];j=((j+1)|er[k]))
{
q=i+c[k][j];
if(q<=m)
{
f[I][q][j]=(f[I][q][j]+f[I-1][i][j-er[k]])%mo;
f[I][q][j]=(f[I][q][j]+f[I][i][j-er[k]])%mo;
}
}
jcn[n]=ksm(JC(1,n),mo-2);
fod(i,n-1,1)jcn[i]=jcn[i+1]*((LL)i+1)%mo;
fo(I,0,m)
{
ans=0;
fo(i,1,min(n,m1))ans=(ans+(LL)f[i][I][er[n+1]-1]*C(m1,i)%mo)%mo;
printf("%lld\n",ans);
}
return 0;
}