题目
题目给我们的这个东西可以转化为一棵\(k\)叉树,有\(n+m\)个叶子节点,其中\(m\)个权值为\(1\),\(n\)个权值为\(0\),每个非叶子节点的权值为其儿子的平均值,现在问你根节点的权值有多少种取值。
转化之后发现似乎可做了一点。(当然还是一道神仙题)
我们设\(n\)个权值为\(0\)的叶子节点的深度为\(x_1\sim x_n\),\(m\)个权值为\(1\)的叶子节点的深度为\(y_1\sim y_m\),根节点的权值为\(z\)。
那么有\(z=\sum\limits_{i=1}^mk^{-y_i}=z\)。
并且如果我们把所有叶子节点的权值都设为\(1\),那么树上所有点的权值都为\(1\),\(z\)也不例外,\(\sum\limits_{i=1}^mk^{-y_i}+\sum\limits_{i=1}^nk^{-x_i}=1\)即\(\sum\limits_{i=1}^nk^{-x_i}=1-z\)。
我们将\(z\)写成\(k\)进制下的小数形式,\(z=0.\overline{c_1\cdots c_l}\)。
那么对于一个\(k^{-y_i}\),它会对某一个\(c\)贡献一。
因此在不考虑进位的情况下,\(\sum\limits_{i=1}^lc_i=m\)。
进位实质上就是某一位\(-k\),高位\(+1\),反映到数位和上就是\(-(k-1)\)。
因此在考虑进位的情况下,\(\sum\limits_{i=1}^lc_i\equiv m(\mod k-1)\)。
当然也有\(\sum\limits_{i=1}^lc_i\le m\)。
对\(1-z\)做类似的分析。
我们可以发现\(1-z\)的数位和就是\(\sum\limits_{i=1}^l(k-1-c_i)+1=l(k-1)+1+\sum\limits_{i=1}^lc_i\)。
后面那坨就是\(z\)的数位和对吧。
与\(z\)的数位和过程相仿,我们有\(l(k-1)+1+\sum\limits_{i=1}^lc_i\equiv n(mod\ k-1)\)和\(l(k-1)+1+\sum\limits_{i=1}^lc_i\le n\)。
#include<cstdio> #include<cctype> const int N=2007,P=1000000007; int inc(int a,int b){return a+=b,a>=P? a-P:a;} int dec(int a,int b){return a-=b,a<0? a+P:a;} int read(){int x;scanf("%d",&x);return x;} int max(int a,int b){return a>b? a:b;} int f[N<<1][N][2],s[N]; int main() { int n=read(),m=read(),k=read(),i,j,ans=0; f[0][0][0]=1; for(i=1;i<=max(n,m)<<1;++i) { s[0]=inc(f[i-1][0][1],f[i-1][0][0]); for(j=1;j<=m;++j) s[j]=inc(s[j-1],inc(f[i-1][j][0],f[i-1][j][1])); for(j=0;j<=m;++j) { f[i][j][0]=dec(s[j],s[j-1]); if(j) f[i][j][1]=dec(s[j-1],(j>=k? s[j-k]:0)); } for(j=0;j<=m;++j) if(j%(k-1)==m%(k-1)&&(i*(k-1)+1-j)%(k-1)==n%(k-1)&&i*(k-1)+1-j<=n) ans=inc(ans,f[i][j][1]); } printf("%d",ans); }