题目大意:
给定 n n n个0和 m m m个1,每次可以选择 k k k个数删去它们,然后把它们的平均数写上去。
求最后剩下的数有几种。
答案对 1 e 9 + 7 1e9+7 1e9+7取模
保证 n + m − 1 n+m-1 n+m−1能被 k k k整除
s o l : sol: sol:
把这个问题转化为 k k k叉树的模型。
其有 n + m n+m n+m个叶子结点。
其中有 n n n个写着0, m m m个写着1。
对于非叶子节点,它的值就是它的儿子节点的平均值。
假设这
n
n
n个0的深度分别是
d
n
i
dn_i
dni,
m
m
m个1的深度为
d
m
i
dm_i
dmi,那么根节点的数就是
∑
i
=
1
m
(
1
k
)
d
m
i
\sum_{i=1}^{m}\left(\frac{1}{k}\right)^{dm_i}
i=1∑m(k1)dmi
显然,如果所有叶节点都是1的话那么根节点也是1,所以
∑
i
=
1
m
(
1
k
)
d
m
i
+
∑
i
=
1
n
(
1
k
)
d
n
i
=
1
\sum_{i=1}^{m}\left(\frac{1}{k}\right)^{dm_i}+\sum_{i=1}^{n}\left(\frac{1}{k}\right)^{dn_i}=1
i=1∑m(k1)dmi+i=1∑n(k1)dni=1
若满足这个条件的话,一定能构造出合法的
k
k
k叉树
现在问题成了求有多少个 q q q能写成 n n n个 ( 1 k ) d n (\frac{1}{k})^{dn} (k1)dn,多少个 1 − q 1-q 1−q能写成 m m m个 ( 1 k ) d m (\frac{1}{k})^{dm} (k1)dm相加的形式。
将根节点的权值用 k k k进制小数表示如同 0 , z 1 , z 2 , z 3 , ⋯ , z n , 0 ≤ z i < k 0,z_1,z_2,z_3,\cdots,z_n,0\leq z_i< k 0,z1,z2,z3,⋯,zn,0≤zi<k
不考虑进位的话 ∑ z = m \sum z=m ∑z=m
考虑上进位的话,每次可以将 z i z_{i} zi减去 1 1 1,让 z i + 1 z_{i+1} zi+1加上 k k k
则 ∑ z ≡ m ( m o d k − 1 ) \sum z \equiv m\pmod {k-1} ∑z≡m(modk−1)
假设小数有 l e n len len位,则 1 − q 1-q 1−q的位数和应该是 ( l e n − 1 ) ( k − 1 ) + k − ∑ z = l e n ( k − 1 ) − ∑ z + 1 (len-1)(k-1)+k-\sum z=len(k-1)-\sum z+1 (len−1)(k−1)+k−∑z=len(k−1)−∑z+1
设 f [ i ] [ j ] f[i][j] f[i][j]表示小数点后第 i i i位,每一位的和是 j j j
直接dp就行了。
由于小数的末尾不能是0,所以当第 i i i位的末尾是否是0也应该加进状态里面。
#include<bits/stdc++.h>
using namespace std;
#define f1(a,b,c) for(int c=a;c<=b;c++)
#define f2(a,b,c) for(int c=a;c>=b;c--)
#define f3(a,b,c) for(int c=a;c;c=b)
#define so1(a,n) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define ll long long
#define itn int
#define ubt int
#define mp make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
const int twx=2e3+100;
const int MOD=1e9+7;
const int inf=0x3f3f3f3f;
ll read()
{
ll sum=0;
ll flag=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
{
flag=-1;
}
c=getchar();
}
while(c>='0'&&c<='9')
{
sum=((sum*10)+c-'0');
c=getchar();
}
return sum*flag;
}
int n,m,k;
int asd[twx<<1][twx][2];
int ans;
int sum[twx];
ll add(ll x,ll y)
{
return x+y>=MOD?x+y-MOD:x+y;
}
ll sub(ll x,ll y)
{
return x-y<0?x-y+MOD:x-y;
}
ll mul(ll x,ll y)
{
return 1LL*x*y%MOD;
}
void init()
{
n=read();
m=read();
k=read();
}
void work()
{
asd[0][0][0]=1;
f1(1,n+m,i)
{
sum[0]=add(asd[i-1][0][0],asd[i-1][0][1]);
f1(1,n,j)
{
sum[j]=add(sum[j-1],add(asd[i-1][j][0],asd[i-1][j][1]));
}
f1(0,n,j)
{
asd[i][j][0]=add(asd[i-1][j][0],asd[i-1][j][1]);
if(j)
{
asd[i][j][1]=sub(sum[j-1],(j-k>=0?sum[j-k]:0));
}
}
f1(0,n,j)
{
if(j%(k-1)==n%(k-1)&&(i*(k-1)-j+1)%(k-1)==m%(k-1)&&i*(k-1)-j+1<=m)
{
ans=add(ans,asd[i][j][1]);
}
}
}
}
void print()
{
printf("%d\n",ans);
}
int main()
{
init();
work();
print();
return 0;
}